Monday, 18 November 2024

ASP.NET Hosting Tutorial: Understanding Param Collection in C# 13

Leave a Comment

The params keyword in C# lets developers pass any number of arguments to a method, making it easier to work with lists or arrays. It was first introduced in C# 1.0 and is still useful today. This blog will dive into the new feature in C# 13 related to params usage


Prerequisites

  • Visual Studio 2022 – 17.12 version
  • .NET 9.0

You can download the Visual Studio Community edition from here.

What is param collection?

The params keyword in C# lets a method take a flexible number of arguments as a single parameter, usually as an array. When a parameter is marked with params, the caller can pass either individual values or an array. This makes it easier to call the method, especially when dealing with optional or unknown numbers of values.

For instance

void PrintParamsWithArray(params int[] numbers)
{
    foreach (var number in numbers)
    {
        Console.WriteLine(number);
    }
}
//The usage would be:
PrintParamsWithArray(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Before C# 13, the params keyword could only be used with arrays. However, with this new feature, you can now use params with any collection type.

The recognized collection types are given below.

System.Span<T>, System.ReadOnlySpan<T>, and types that implement System.Collections.Generic.IEnumerable<T> and have an Add method. You can also use interfaces like System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.Generic.ICollection<T>, and System.Collections.Generic.IList<T>, not just specific types.

Let us look at an example.

Use List with params.

internal static class WithList
{
    public static void Display(params List<int> numbers)
    {
        foreach (var number in numbers)
        {
            Console.WriteLine(number);
        }
    }
}
// Usage
Console.WriteLine("Params with List");
WithList.Display([1, 2, 3, 4, 5, 6, 7]);

Use Span with params.

public static void Display(params ReadOnlySpan<int> numbers)
{
    foreach (var number in numbers)
    {
        Console.WriteLine(number);
    }
}
// Usage:
Console.WriteLine("Params with Span");
WithSpan.Display(1, 2, 3, 4, 5);

Let’s run the program, and you’ll see the following output.

The params keyword in C# is a useful tool for managing variable numbers of arguments. Since it was introduced in C# 1.0, it has helped developers write cleaner and more flexible code by making it easier to pass multiple parameters to methods.

Happy Coding!

Best ASP.NET Core 8.0.8 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 8.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

Read More...

Wednesday, 13 November 2024

ASP.NET Hosting Tutorial: Understanding Keyed Services in .NET 8

Leave a Comment

Dependency injection plays a crucial role in every programming language. Microsoft has introduced many new features and significant enhancements in .Net 8. “Keyed Services” is one of the important, powerful enhancements in the dependency injection shipped with .Net Core 8.

In this article, we will explore Keyed Services .Net 8, illustrating with an example. This article is suitable for beginners, intermediate learners, and professionals.

We are going to cover the following in this article.

  1. How do you deal with multiple implementations of the interface prior to Keyed Services?
  2. Introduction of Keyed Services?
  3. Lifetime scope for Keyed Services.
    • AddKeyedSingleton
    • AddKeyedScoped
    • AddKeyedTransient
  4. How to register and resolve dependencies using Keyed Services

Prerequisites

Below are the prerequisites for Keyed Services.

  1. .NET 8 SDK (RC1 or later version)
  2. Visual Studio 2022 version 17.8 or later

Let’s start with the use case of the Keyed Services.

How do you deal with multiple implementations of the interface prior to Keyed Services?

Let’s assume that we want to implement report generator functionality, which can generate reports on XML, CSV, and PDF as per the user's preference.

Now, think how you will implement this prior to .NET 8. Let’s create a demo MVC core project in .NET Core 6.0.

Step 1. Create a .NET Core MVC project using .NET Core 6.0.

Step 2. Create an Interface called “IReportGenerator”.

namespace WebApplication1.Interfaces
{
    public interface IReportGenerator
    {
        string GenerateReport();
    }
}

Step 3. Create Three classes “CSVReportGenerator”, “XmlReportGenerator”, and “And PDFReportGenerator” and implement the “IReportGenerator” interface.

CSVReportGenerator.cs

public class CSVReportGenerator : IReportGenerator
{
    public string GenerateReport()
    {
        // Actual code of CSV report generator
        return "CSV report";
    }
}

XmlReportGenerator.cs

public class XmlReportGenerator: IReportGenerator
{
   public string GenerateReport()
   {
     //actual code of xml report generator
      return "XML Report";
   }
}

PDFReportGenerator.cs

public class PDFReportGenerator: IReportGenerator
{
   public string GenerateReport()
   {
      //actual code of xml report gen
      return "PDF Report";
   }
}

Step 4. Register dependencies in the program.cs file.

builder.Services.AddSingleton<IReportGenerator, XmlReportGenerator>();
builder.Services.AddSingleton<IReportGenerator, PDFReportGenerator>();
builder.Services.AddSingleton<IReportGenerator, CSVReportGenerator>();

We have registered all three classes in the program.cs file.

Step 5. Make the code changes in the HomeController.

public class HomeController: Controller
{
   private readonly ILogger<HomeController> _logger;
   private readonly IReportGenerator _reportGenerator;
   public HomeController (ILogger<HomeController> logger, IReportGenerator reportGenerator)
   {
      _logger logger;
      _reportGenerator = reportGenerator;
   }
   public IActionResult Index()
   {
       ViewBag.ReportGenerator=_reportGenerator.GenerateReport();
       return View();
   }
}

In the above code, we have injected “IReportGenerator” as a parameter in the controller constructor, which is then called the GenerateReport method in the index action method.

Step 6. Make code changes in the Index.cshtml file.

In the code below, we are printing the GeneratorReport output in the welcome message.

@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome from @ViewBag.ReportGenerator</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

Step 7. Run the application and observe the output.

Output

We observed that only the last registered service was retrieved. In this case, the CSV report is the last registered service.

Now, the next question is how to get another registered service, if required, like XML Report or PDF Report. We can make the code changes below in the HomeController and achieve it.

public class HomeController: Controller
{
  private readonly ILogger<HomeController> _logger;
  private readonly IEnumerable<IReportGenerator> _reportGenerator;
  public HomeController (ILogger<HomeController> logger, IEnumerable<IReportGenerator> reportGenerator)
  {
    _logger logger;
    _reportGenerator = reportGenerator;
  }
  public IActionResult Index()
  {
     ViewBag.ReportGenerator=_reportGenerator.ElementAt(0).GenerateReport();
     return View();
  }
}

Execute the program and see the output. This time, we will get the XmlReport.

Introduction of Keyed Services

Keyed Services allows us to register and retrieve dependency injection using Key.

You can register and retrieve multiple implementations of the same interface using a key.

Lifetime scope for Keyed Services

Microsoft introduced three new extension methods for the Lifetime scope of keyed services.

  1. AddKeyedSingleton
  2. AddKeyedScoped
  3. AddKeyedTransient

These extension methods are like AddSinglton, AddScoped, and AddTransient methods in .Net core, except it allow us to use “key” to define lifetime scope of dependencies.

How to register and resolve dependencies using Keyed Services?

Let’s create the same report example using .Net 8 Keyed Service.

Step 1. Create a .Net Core MVC project using .Net Core 8.0

Step 2. Create interface “IReportGenerator” and three classes “CSVReportGenerator”, “PDFReportGenerator”, and “XMLReportGenerator” in the previous section of Step 2 and Step 3.

Step 3. Register dependencies in the Program.cs file like below.

builder.Services.AddKeyedSingleton<IReportGenerator, XmlReportGenerator>("XML");
builder.Services.AddKeyedSingleton<IReportGenerator, PDFReportGenerator>("PDF");
builder.Services.AddKeyedSingleton<IReportGenerator, CSVReportGenerator>("CSV");

we have used “AddKeyedSingleton” to register dependencies.

Step 4. Make the below code changes in HomeController.

public class HomeController: Controller
{
  private readonly ILogger<HomeController> _logger;
  private readonly IReportGenerator _xmlreportGenerator;
  private readonly IReportGenerator _pdfreportGenerator;

  public HomeController (ILogger<HomeController> logger, [FromKeyedServices ("XML")] IReport
  Generator xmlReportGenerator, [FromKeyedServices ("PDF")] IReportGenerator pdfReportGenerator)
  {
    _logger logger;
    _xmlreportGenerator = xmlReportGenerator;
    _pdfreportGenerator = pdfReportGenerator;
  }
  public IActionResult Index()
  {
    ViewBag.ReportGenerator = _xmlreportGenerator.GenerateReport() + "Second Report +
    _pdfreportGenerator.GenerateReport();
    return View();
  }
}

In this code, we have used [FromKeyedServices] to retrieve dependencies based on the Key.

Step 5. Copy index.cshtml code from the previous example, step 6.

Step 6. Execute the program and see the output.

Output

I hope you enjoyed this article and learned something new.

Best ASP.NET Core 8.0.8 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 8.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

Read More...

Tuesday, 5 November 2024

Learning to Use NCache for Session Management in.NET

Leave a Comment

You may already be aware that HTTP is a stateless protocol and that the web server does not remember the user's status in between requests if you have been creating web apps for a while. It is challenging to provide the consumer with a personalized experience because of this limitation. To preserve user-specific data across several requests, developers must employ a variety of strategies, including session management. I'll give a quick rundown of sessions and some of their drawbacks in this post. Next, I'll go over how managing sessions in medium-to large-scale enterprise systems can benefit greatly from a distributed, highly scalable cache like NCache. Additionally, I will demonstrate how to set up, install, and utilize NCache in your ASP.NET Core web apps.

An Overview of.NET Session Management

One of the most important aspects of any online application is session management. It enables the server to monitor users over several requests and save user-specific data, like shopping cart details and authentication status. For scalability and dependability, session data can also be kept in a distributed cache like NCache, but it is usually kept on server memory or disk. A session ID is a unique session identification that is assigned to each user and is either supplied in the URL or kept in a cookie. On subsequent queries, the session data is retrieved using this session ID. One of the following places can be used to store session data in.NET. 

  1. In-Process: The session data is stored in the web server's memory. This is the fastest option, but it is not very scalable because session data is available memory, and it can easily be lost if the application pool is recycled or if the web app is hosted on multiple servers and a load balancer sends the request to another server.
  2. State Server: The session data is stored in a dedicated state server, separate from the web server. This allows session data to persist even if the application pool or web server is restarted. The State Server runs as a Windows service, and session data is accessed over the network, making it suitable for load-balanced environments. However, using a State Server can introduce network latency compared to in-process session storage, though it improves scalability and session persistence.
  3. SQL Server: The session data is stored in an SQL Server database, which provides persistent storage if you are using multiple web servers or have a load-balanced environment. This approach is more resilient than in-memory sessions but it can introduce overhead due to database read/write operations. This is the best option if your application requires high availability, data persistence, and scalability, and you can slightly compromise on performance.
  4. Distributed Caching (e.g. NCache): Distributed caching is a method of storing data across multiple servers or nodes in a network, allowing web applications to access cached data more efficiently and reliably. This method is more suitable in cloud-native and distributed applications where you want to keep cached data on the server that is nearest to the user.

Limitations of Traditional Session Management

Although session management seems like a very attractive and useful feature to most developers, as they gain more experience, they realize that there are several limitations to using traditional session management techniques. Some of the limitations are mentioned below.

  1. Scalability Issues: If you are using in-memory sessions, your sessions are tied to a specific server. This creates problems in load-balanced or multi-server environments, where users may be routed to different servers, causing session data loss unless you are using sticky sessions.
  2. Memory Consumption: If you are storing a large amount of session data in the server’s memory, your application will consume significant memory resources, especially if you have a large-scale application with millions of users. This can not only degrade application performance, but it also increase the risk of server crashes.
  3. Session Data Loss: If you are using in-memory session storage, your session data can be lost if the server is restarted or crashes. This disrupts user experiences and requires external solutions to ensure persistence.
  4. Session Timeout Limitations: Fixed session timeouts can frustrate users, especially if they lose their session due to inactivity. Managing these timeouts effectively while balancing resource consumption can be challenging for most beginner and intermediate-level developers.
  5. Security Concerns: Traditional session management often relies on cookies to store session IDs, making them vulnerable to session hijacking or cross-site scripting (XSS) attacks if not properly secured.
  6. Managing Large Sessions: Sessions that store large amounts of data can slow down requests, as reading and writing session data becomes more resource-intensive, particularly when stored in databases or other persistent stores.

The limitations mentioned above often prompt developers to adopt more high-performance and scalable solutions like NCache that can not only solve all of the problems but can also provide many additional features to cache session data for your applications.

Introduction of NCache for .NET Developers
NCache is a powerful, distributed caching solution designed specifically for .NET applications. It enhances application performance and makes the application more scalable by providing both an in-memory and a distributed cache across multiple servers. NCache reduces database load and speeds up data access in high-traffic applications. NCache supports a wide range of caching scenarios, such as simple key-value storage, transactional data caching, or session caching. The following diagram shows how the NCache cluster can sit between your .NET applications and the database and cache data for multiple applications.

 

NCache provides various APIs to add, update, or remove data to/from cache. The data can be stored as a single item or as bulk data. Developers also have the option to store data either synchronously or asynchronously as per their application requirements. The data stored in the cache can be a primitive data type such as int, double, bool, object, etc. or it can be any custom serializable class object, e.g. Product, Order, etc.

Advantages of using NCache for Session Management

Following are some of the benefits of using NCache as your ASP.NET Core Session State Provider.

  1. High Availability: NCache replicates sessions across multiple cache nodes to ensure that the session data is always available, even during server failures. NCache provides a self-healing peer-to-peer clustering architecture that has no single point of failure. This dynamic clustering also allows us to add or remove any cache server from the cluster without stopping the cache or the applications.
  2. Multi-Region Replication: NCache can also replicate ASP.NET Core sessions across multiple regions (data centers) to ensure that the sessions remain safe, even if a data center goes offline.
  3. Distributed & Scalable: NCache stores session data in a distributed cache that allows your sessions to scale across multiple servers. This also eliminates the single-point-of-failure issues.
  4. Improved Performance: It enhances the performance of session retrieval by caching session data in memory, reducing the load on databases or slower storage systems. NCache also uses its custom serialization method called ‘Compact Serialization’ which is much faster than the slow serialization method available in .NET.
  5. Session Failover and Persistence: In the event of an application server failure, NCache automatically handles session failover to make sure that the sessions are not lost. It also supports persistent session storage, allowing session data to survive across application restarts.
  6. Support for Large Sessions: NCache can handle large session objects, distributing them efficiently across cache nodes.
  7. Cross-Platform Compatibility: NCache offers flexibility for different development environments by supporting both ASP.NET and ASP.NET Core applications.
  8. Increased Web Farm Efficiency: In multi-server environments, NCache eliminates the need for "sticky sessions" by synchronizing the session state across all servers.
  9. Enhanced Security: With encryption and secure communication between cache clients and servers, NCache ensures that sensitive session data remains protected.

Installing and Configuring NCache in ASP.NET Core App

Before we learn how to use NCache, we need to make sure we have installed and configured NCache on the development machine. There are multiple versions of NCache available, and you can choose the specific version as per your application requirements.

  1. NCache Open Source: A free, open-source, and community-supported version of NCache that provides basic distributed caching features for small to medium applications.
  2. NCache Professional: This is a paid version of NCache and it is suitable for small to medium-sized business applications. It provides additional features such as client cache and better performance optimizations.
  3. NCache Enterprise: The most advanced version of NCache that provides the most advanced caching features, including disaster recovery, high availability, and performance monitoring, and it's the best choice for large enterprise applications.

Note. NCache Professional and Enterprise versions are also available as SaaS in both Azure and AWS marketplaces.

The next thing we need to decide is how we want to install and use NCache. We can choose one of the following options.

  1. NCache Cache Server: We can download and install the NCache cache server from the NCache official download page to enjoy features like distributed caching, high availability, replication, and scalability.
  2. NCache Docker Image: We can spin up an NCache cache server in a Docker container if you want to avoid installing NCache directly on our system.
  3. NCache Client (In Memory Cache): We can skip NCache cache server installation and directly use NCache-related Nuget packages in our .NET projects to use in-memory cache for quick testing and proof of concepts.

For this article, I have downloaded the Open Source version of NCache. Let’s create a new ASP.NET MVC Project in Visual Studio 2022 using .NET 8 and run the following commands in the Package Manager Console to install the Open Source version of NCache.

Package Manager Console

Install-Package Alachisoft.NCache.OpenSource.SDK

Install-Package NCache.Microsoft.Extensions.Caching.OpenSource

Next, we need to configure NCache, and we have two options.

  1. We can specify all configurations through code in the Program.cs file.
  2. We can specify all configurations in JSON format in the appsettings.json file.

Let’s use option one and configure NCache in the Program.cs file.

Program.cs

using Alachisoft.NCache.Caching.Distributed;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddNCacheDistributedCache(configuration =>
{
    configuration.CacheName = "democache";
    configuration.EnableLogs = true;
    configuration.ExceptionsEnabled = true;
});

builder.Services.AddControllersWithViews();

var app = builder.Build();

The above code snippet uses the AddNCacheDistributedCache method to configure NCache. This method adds NCache as the default distributed cache implementation of the IDistributedCache interface. The method requires CacheName and some other optional configurations.

Next, we need to add the following code in our HomeController.

HomeController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using System.Text;

namespace AspNetCoreNCacheDemo.Controllers
{
    public class HomeController : Controller
    {
        private readonly IDistributedCache _cache;

        public HomeController(IDistributedCache cache)
        {
            _cache = cache;
        }

        public IActionResult Index()
        {
            string cachedValue = string.Empty;

            byte[] cacheData = _cache.Get("MyCacheKey");    // Get Data From Cache

            if(cacheData != null)
            {
                cachedValue = Encoding.UTF8.GetString(cacheData);
            }

            if (string.IsNullOrEmpty(cachedValue))
            {
                cachedValue = "Cache Data";
                cacheData = Encoding.UTF8.GetBytes(cachedValue);

                _cache.Set("MyCacheKey", cacheData);        // Set Data From Cache
            }

            ViewBag.CachedData = cachedValue;

            return View();
        }
    }
}

The above code injects the IDistributedCache instance into the constructor of the controller and then uses the Get and Set methods to add and retrieve data from the cache.

Using NCache for ASP.NET Core Session Management

To use NCache ASP.NET Core Session Provider for session management we need to install the following Nuget package in our project.

Package Manager Console

Install-Package AspNetCore.Session.NCache.OpenSource

Next, we need to initialize the NCache sessions service in the Program.cs file as follows.

Program.cs

builder.Services.AddNCacheSession(configuration =>
{
    configuration.CacheName = "demoCache";
    configuration.EnableLogs = true;
    configuration.SessionAppId = "demoApp";
    configuration.SessionOptions.IdleTimeout = 5;
    configuration.SessionOptions.CookieName = "AspNetCore.Session";
});

The complete details of all session-related options are available in NCache docs.

Next, we need to configure the HTTP request pipeline by adding middleware using the UserNCacheSession method.

Program.cs

app.UseNCacheSession();

After configuring NCache as the default cache for ASP.NET Core Sessions, you can perform all session-specific operations without modifying any code, and all sessions will be stored in the distributed NCache. You just need to make sure that if you are storing custom objects in the session, then they are marked as serializable. You can do this by adding the [Serializable] attribute to your custom object class definition.

Let’s implement a small To Do list app that will display a To Do list to the user and will allow the user to add a new To-Do item to the list. We will then store the To Do list in the ASP.NET core session that will use NCache behind the scenes.

First of all, create the following ToDo model class with a single Name property.

ToDo.cs

[Serializable]
public class ToDo
{
    public string Name { get; set; }
}

Next, implement the following Index action methods in the HomeController that will fetch the list ToDo list from the session using the GetObject method and display it on the page.

HomeController.cs

public class HomeController : Controller
{
    public IActionResult Index()
    {
        var list = HttpContext.Session.GetObject<List<ToDo>>("ToDoList");
        return View(list);
    }
}

The razor view page of the above action method will iterate over the ToDo items and will render the names of all ToDo items in a simple table. It also has a Create New button that will redirect the user to another page where the user can add a new ToDo Item.

Index.cshtml

@model IEnumerable<ToDo>

@{
    ViewData["Title"] = "Home Page";
}

<h2>To Do</h2>
<a asp-action="Create" class="btn btn-success mb-3">Create New</a>

@if (Model != null)
{
    <table class="table table-bordered table-striped ">
        <thead>
            <tr class="bg-warning ">
                <td>Name</td>
            </tr>
        </thead>
        <tbody>

            @foreach (var item in Model)
            {
                <tr>
                    <td>@item.Name</td>
                </tr>
            }

        </tbody>
    </table>
}

If you will test your page at this point, you should see the following output in the browser. 


Next, implement the following Create action methods in the HomeController. The first method will render the Create page in the browser using the HttpGet request. The second method will be called when the user submits the Create page by providing a new ToDo item name.

HomeController.cs

public IActionResult Create()
{
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(ToDo todo)
{
    if (ModelState.IsValid)
    {
        var list = HttpContext.Session.GetObject<List<ToDo>>("ToDoList");

        if(list == null)
        {
            list = new List<ToDo>();
        }

        list.Add(todo);

        HttpContext.Session.SetObject("ToDoList", list);

        return RedirectToAction("Index");
    }

    return View(todo);
}

The above Create method first fetches the ToDo ToDo list from the session, and if it doesn’t find any list in the session, it creates a new list. Next, it adds the ToDo item to the list, and finally, it puts the list back in the session using the SetObject method.

Please note that the GetObject and SetObject methods used above are not the built-in methods of ASP.NET Core. I implemented the following extension methods to easily add or retrieve custom objects in or from the session.

SessionExtensions.cs

public static class SessionExtensions
{
    public static void SetObject(this ISession session, string key, object value)
    {
        session.SetString(key, JsonSerializer.Serialize(value));
    }

    public static T GetObject<T>(this ISession session, string key)
    {
        var value = session.GetString(key);
        return value == null ? default(T) : JsonSerializer.Deserialize<T>(value);
    }
}

Following is the Razor view page of the Create action method.

Index.cshtml

@model ToDo

<h2>Create</h2>

<div class="row alert alert-primary">
    <div class="col-md-4">
        <form asp-action="Create">
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
            </div>
            <br />
            <input type="submit" value="Create" class="btn btn-success" />
        </form>
    </div>
</div>

You can now run the application and try to click the “Create New” button. You should see the page similar to the following screenshot.


Try to create some ToDo items using the above form, and all items will be added to the list and session.

Summary

NCache is an ideal solution for managing sessions in high-traffic or distributed web applications. In this article, we learned how application resilience and user experience can be enhanced using NCache features like session replication, high availability, and fault tolerance. We also learned how to install, configure, and use NCache for simple data caching as well as session data caching.

ASP.NET Core 9.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 9.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

Read More...

Tuesday, 29 October 2024

JWT Token Based Implementation using ASP.NET Core Web API

Leave a Comment

JSON Web Tokens (JWT) are used for securely transmitting information between parties as a JSON object. JWT is typically used for authentication and authorization. In this article, I'll walk you through how to implement JWT authentication in an ASP.NET Core Web API.

Steps to Implement JWT Token-Based Authentication
Create an ASP.NET Core Web API Project
  1. Open Visual Studio and create a new project.
  2. Select ASP.NET Core Web API template.
  3. Configure the project as per your requirements and click Create
Install Required NuGet Packages
  1. To implement JWT, you will need the following NuGet package.
  2. Microsoft.AspNetCore.Authentication.JwtBearer
  3. Install it via NuGet Package Manager
  4. 3. Configure JWT in appsettings.json
  5. In your appsettings.json, configure the JWT settings.
    {
      "JwtSettings": {
        "SecretKey": "wvFwnwxh7GucmY898kQdKzEU5TjE18SQ",  // Use a strong secret key
        "Issuer": "yourdomain.com",
        "Audience": "yourdomain.com",
        "ExpiryInMinutes": 60
      }
    }
Create a JWT Helper Class

Create a helper class that will be responsible for generating the JWT token.

public class JwtTokenHelper
{
    private readonly IConfiguration _configuration;

    public JwtTokenHelper(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string GenerateToken(string username)
    {
        var secretKey = Encoding.ASCII.GetBytes(_configuration["JwtSettings:SecretKey"]);
        var tokenHandler = new JwtSecurityTokenHandler();
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.Name, username)
            }),
            Expires = DateTime.UtcNow.AddMinutes(int.Parse(_configuration["JwtSettings:ExpiryInMinutes"])),
            Issuer = _configuration["JwtSettings:Issuer"],
            Audience = _configuration["JwtSettings:Audience"],
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }
}

Configure JWT Authentication in Startup.cs or Program.cs

In Program.cs, you need to configure JWT authentication in the builder. Services and middleware pipeline. Here's the step-by-step process.

using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    // Add the JWT Bearer definition to Swagger
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n " +
                      "Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\n" +
                      "Example: \"Bearer 12345abcdef\"",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    c.AddSecurityRequirement(new OpenApiSecurityRequirement()
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                },
                Scheme = "oauth2",
                Name = "Bearer",
                In = ParameterLocation.Header
            },
            new List<string>()
        }
    });
});

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = builder.Configuration["JwtSettings:Issuer"],
        ValidAudience = builder.Configuration["JwtSettings:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8
Steps to Configure Swagger to Pass JWT Tokens
Install-Package Swashbuckle.AspNetCore

Ensure you have Swashbuckle.AspNetCore is installed in your project.

dotnet add package Swashbuckle.AspNetCore
Create Login Endpoint

You can then create a Login endpoint inside a controller to issue JWT tokens.

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly JwtTokenHelper _jwtTokenHelper;

    public AuthController(JwtTokenHelper jwtTokenHelper)
    {
        _jwtTokenHelper = jwtTokenHelper;
    }

    [AllowAnonymous]
    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginModel loginModel)
    {
        // For example, this is a simple check, replace it with actual user validation
        if (loginModel.Username == "test" && loginModel.Password == "password")
        {
            var token = _jwtTokenHelper.GenerateToken(loginModel.Username);
            return Ok(new { Token = token });
        }
        return Unauthorized();
    }
}

public class LoginModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Protecting Routes

Finally, you can protect specific routes by adding the [Authorize] attribute in your controllers.

[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get([FromQuery] int days)
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

Testing JWT in Postman

  1. Login: Send a POST request to /api/auth/login with a valid username and password.
  2. Token: Copy the token from the login response.
  3. Protected Resource: Access the /API/WeatherForecast endpoint and include the JWT in the Authorization header:

Step 1. Obtain a JWT Token in Swagger.

  1. Create a Login Request
    • Open Postman and create a new request.
    • Set the request type to POST.
    • Enter the URL for your login endpoint (e.g., http://localhost:5000/api/auth/login).
  2. Set the Request Body
    • In the Body tab, select raw and set the format to JSON.
    • Enter the login credentials. For example
      {
          "username": "your-username",
          "password": "your-password"
      }


  1.  Send the Request
  2. Click the Send button.
  3. If the credentials are valid, you should receive a response containing the JWT token. The response might look like this.


  4. Copy the token from the login response.
  5. Create a GET request for a protected route.
  6. Set Authorization to Bearer Token and paste the JWT.

Example

Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6InRlc3QiLCJuYmYiOjE3Mjk3Nzc1MDcsImV4cCI6MTcyOTc4MTEwNywiaWF0IjoxNzI5Nzc3NTA3LCJpc3MiOiJ5b3VyZG9tYWluLmNvbSIsImF1ZCI6InlvdXJkb21haW4uY29tIn0.ZOwHBIvd2wnjIW3NFOKRSc7QUkiQ2kybEc0yiYMfeN4
Bash

Send the request and check the response.

Summary

We have implemented JWT (JSON Web Token) authentication to enhance security and streamline user authentication in our application.

ASP.NET Core 9.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 9.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

Read More...