Distributed Sessions in ASP.NET Core MVC

Distributed or Out-Proc Sessions in ASP.NET Core MVC

In this article, I will discuss Distributed or Out-Proc Sessions in ASP.NET Core MVC Applications, as well as the differences between in-memory and distributed sessions with examples. In our previous article, we discussed Implementing In-Memory (In-Proc) Sessions in ASP.NET Core MVC Applications. 

What are Distributed (Out-Proc) Sessions in Web Applications?

Distributed (Out-Proc) Sessions in web applications refer to a method of session management where session data is stored outside the web server’s memory, typically in an external store. This approach is commonly used in scenarios where applications are deployed across multiple servers (load balancing) or in cloud environments, requiring a shared and persistent session state across different instances of the application. This approach allows session data to be shared across multiple instances or servers in a web farm or cloud environment.

How Does the Distributed Sessions Works in Web Application?

Let us understand the Step by Step Process of How Distributed Sessions Work in Web Applications:

Step 1: User Initiates a Session

When a user accesses a web application for the first time, the server creates a new session to store information about the user’s interaction with the application.

Step 2: Session ID Generation

The server generates a unique Session ID to identify this particular user session. This Session ID is usually stored in a cookie on the user’s browser.

Step 3: Storing Session Data

Instead of storing the session data in the web server’s memory (In-Proc), the application stores session data in an external storage system such as a database, Redis, or another distributed caching mechanism.

Step 4: Saving Session Data to External Storage

When the application needs to store data in the session (e.g., user preferences, shopping cart items), it sends this data along with the Session ID to the external storage system. This typically involves:

  • Serializing the session data into a format suitable for storage.
  • Connecting to the external storage system.
  • Storing the session data using the Session ID as the key.
Step 5: Retrieving Session Data

On subsequent requests, the user’s browser sends the Session ID cookie back to the server. The server uses this Session ID to retrieve the session data from the external storage:

  • The server reads the Session ID from the request.
  • It connects to the external storage system.
  • It retrieves and deserializes the session data associated with that Session ID.
Step 6: Using Session Data

The retrieved session data is then used by the application to maintain the user’s state, such as keeping the user logged in, showing their preferences, or displaying the contents of their shopping cart.

Step 7: Updating Session Data

If the session data changes (e.g., the user adds an item to their shopping cart), the server updates the session data in the external storage:

  • The session data is updated in memory.
  • The updated session data is serialized and sent to the external storage system.
  • The external storage system updates the stored data associated with the Session ID.
Step 8: Session Expiry

Sessions have a timeout period, after which they expire and are no longer valid. This timeout can be configured. The external storage system is responsible for removing expired session data.

Implementing Distributed (Out-Proc) Sessions in ASP.NET Core MVC using SQL Server:

Let us Implement Distributed Sessions in ASP.NET Core MVC and store the Session data in the SQL Server database. Implementing distributed (Out-Proc) sessions in ASP.NET Core MVC using SQL Server involves configuring our application to store session data in an SQL Server database and setting up our ASP.NET Core application to use this store for session management. This allows session data to be shared across multiple servers, making it ideal for applications that are deployed in a load-balanced environment or need to maintain state across server restarts. Let us proceed and implement this step by step:

Install Required Packages

First, add the following NuGet packages.

  • Microsoft.EntityFrameworkCore.SqlServer for Entity Framework Core with SQL Server.
  • Microsoft.Extensions.Caching.SqlServer for SQL Server distributed caching.

You can install the above packages using NuGet Package Manager for Solution or Package Manager Console. Please execute the following command in the Package Manager Console to install the Packages:

Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.Extensions.Caching.SqlServer

Configure SQL Server for Session Storage

First, create a database in the SQL Server database with the SessionDB (CREATE DATABASE SessionDB;), where we will store the session data. Before proceeding, ensure you have a SQL Server database available. You’ll need to create a table to store session data. The dotnet SQL-cache command is part of the .NET Core CLI, specifically designed for working with distributed SQL server cache. If you’re unable to find this command, it’s likely that the necessary tool has not been installed on your system. To install it, you should run the following command:

dotnet tool install –global dotnet-sql-cache

The SQL-cache create tool can be used to create the Session table in the SQL server database. Run the following command in your terminal, replacing the placeholders with your database details. The following command creates a table named MySessions in the specified database to store session data.

dotnet sql-cache create “Data Source=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Initial Catalog=SessionDB;Integrated Security=True;TrustServerCertificate=True” dbo MySessions

Once the above command is executed successfully, the MySessions table must be created in the SessionDB database with the following structure:

Distributed Sessions in ASP.NET Core MVC

Understanding the Table Structure:

  • ID: This is a unique identifier for each session. It’s typically a string representing the session key, which the ASP.NET Core application uses to identify and retrieve the session data for each request.
  • Value: The Value column holds the serialized session data. When your application stores any data in the session (using HttpContext.Session.SetString, SetInt32, Set, etc.), ASP.NET Core serializes this data into a binary format and stores it in this column.
  • ExpiresAtTime: This column stores the timestamp at which the session will expire. The session state middleware in ASP.NET Core checks this value to determine if the session data is still valid. If the current time is greater than the ExpiresAtTime, the session is considered expired, and the middleware will not return the stored data.
  • SlidingExpirationInSeconds: This column is used when the session is configured for sliding expiration. Sliding expiration resets the session’s expiration time only if the session is accessed. This value represents the amount of time (in seconds) to extend the session’s life from the current moment when a request is made. If this column is used, each time the session is accessed, the ExpiresAtTime is updated to be the current time plus the value in SlidingExpirationInSeconds.
  • AbsoluteExpiration: This column is used for an absolute expiration policy, where the session will expire at a specific point in time, regardless of whether it’s accessed. It’s an alternative to sliding expiration. This would be set to a specific point in time (timestamp), after which the session should no longer be considered valid.
Configuring Connection String:

Storing the Connection string in the AppSettings.json file. So, modify the AppSettings.json file as follows. You can see we have added the ConnectionStrings section here.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "EFCoreDBConnection": "Server=LAPTOP-6P5NK25R\\SQLSERVER2022DEV;Database=SessionDB;Trusted_Connection=True;TrustServerCertificate=True;"
  }
}
Step 4: Configure DbContext

Create a DbContext class for the application. Add a class named EFCoreDBContext.cs within the Models folder, and then copy and paste the following code.

using Microsoft.EntityFrameworkCore;

namespace SampleMVCWeb.Models
{
    public class EFCoreDbContext : DbContext
    {
        //Constructor calling the Base DbContext Class Constructor
        public EFCoreDbContext(DbContextOptions<EFCoreDbContext> options) : base(options)
        {
        }
    }
}
Configure Services for Distributed Cache

In your Program.cs file, configure Entity Framework Core, and the Distributed SQL Server cache. In this configuration, replace EFCoreDbContext and EFCoreDBConnection with your specific Entity Framework Core context and connection string. The following code is self-explained, so please read the comment lines for a better understanding.

// Add and configure the Entity Framework Core DbContext service
builder.Services.AddDbContext<EFCoreDbContext>(options =>
    // Configure the DbContext to use SQL Server with the connection string from configuration
    options.UseSqlServer(builder.Configuration.GetConnectionString("EFCoreDBConnection"))
);

// Add and configure the Distributed SQL Server Cache service for session storage
builder.Services.AddDistributedSqlServerCache(options =>
{
    // Set the connection string for connecting to the SQL Server where session data will be stored
    options.ConnectionString = builder.Configuration.GetConnectionString("EFCoreDBConnection");

    // Set the database schema where the session table will be located
    options.SchemaName = "dbo";

    // Set the table name where session data will be stored
    options.TableName = "MySessions";
});

// Add and configure the Session service
builder.Services.AddSession(options =>
{
    // Set the idle timeout for the session; the session will expire if inactive for this duration
    options.IdleTimeout = TimeSpan.FromMinutes(30);

    // Set the HttpOnly property to true to prevent client-side scripts from accessing the session cookie
    options.Cookie.HttpOnly = true;

    // Mark the session cookie as essential, which means it will be included even if the user has not given consent for non-essential cookies
    options.Cookie.IsEssential = true;
});
Configure Session Middleware

In the same Program.cs file, add the session middleware to the application’s request pipeline.

app.UseRouting();
app.UseAuthorization();

//Configuring Session Middleware in ASP.NET Core
//It should and must be configured after UseRouting and before MapControllerRoute
app.UseSession();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
Using Sessions in Controllers

You can now use sessions in your controllers similar to in-memory sessions:

using Microsoft.AspNetCore.Mvc;

namespace SampleMVCWeb.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            HttpContext.Session.SetInt32("UserId", 123456);
            HttpContext.Session.SetString("UserName", "info@dotnettutorials.net");
            return View();
        }

        public IActionResult Privacy()
        {
            var sessionUserName = HttpContext.Session.GetString("UserName");
            ViewBag.UserName = sessionUserName;

            var sessionUserId = HttpContext.Session.GetInt32("UserId");
            ViewBag.UserId = sessionUserId;
            return View();
        }
    }
}

Next, modify the Index.cshtml view as follows:

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

<div class="text-left">
    <h2>Index Page</h2>
</div>

Next, modify the Privacy.cshtml view as follows:

@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<div class="text-left">
    <b>User Name:</b>@ViewBag.UserName
    <br />
    <b>User Id:</b> @ViewBag.UserId
</div>

Now, run the application and visit the Index action method where we are saving the session data. Now, once you access the Home Page, go to the database and check the MySession data, and you should see the following:

Note: The AbsoluteExpiration column is not used by default in the SQL Server distributed cache. This column is part of the schema to ensure compatibility with other potential caching implementations that might use absolute expiration. However, in the default setup with ASP.NET Core and SQL Server, this column is left null and does not play a role in the expiration mechanism.

How Do We Delete the Distributed Session Data from the SQL Server Database?

Managing and Deleting Expired Session data from the SQL Server database in an ASP.NET Core MVC application, especially when using distributed sessions, is important for maintaining performance and efficient data management. SQL Server doesn’t automatically clean up expired sessions. Therefore, we need to implement a mechanism to remove old session data periodically. You can create an SQL Server Agent Job or a scheduled task that runs an SQL script to delete expired sessions. Here is an example SQL script that you could run:

DELETE FROM [YourSessionTable] WHERE ExpiresAt < GETUTCDATE();

Replace [YourSessionTable] with the name of your session table. This script deletes all expired sessions according to the ExpiresAt column.

In-Memory or In-Proc vs. Distributed or Out-Proc Sessions in ASP.NET Core MVC

In ASP.NET Core MVC, session management can be categorized into two main types: In-Memory (In-Proc) sessions and Distributed (Out-Proc) sessions. Each type has its advantages and use cases depending on the application requirements. Let us understand the differences between these two approaches in detail:

In-Memory (In-Proc) Sessions in ASP.NET Core MVC

In-memory sessions store session data on the web server’s memory (RAM). Data is tied to the application’s process and is lost if the application restarts or crashes. It is suitable for applications running on a single server.

Advantages of In-Memory (In-Proc) Sessions:
  • In-memory sessions are faster because they are stored directly in the server’s memory, and hence, data access is done from memory.
  • This approach is easy to set up and doesn’t require additional infrastructure or configuration.
Disadvantages of In-Memory (In-Proc) Sessions:
  • In-memory sessions are not ideal for load-balanced or multi-server applications that need to scale out across multiple servers because the session data is not shared across the servers.
  • If the server crashes or restarts, all the session data is lost, which can be problematic for applications that rely heavily on session data.
  • As the number of users increases, the web server’s memory usage can also increase, which can impact the server’s overall performance.
Distributed (Out-Proc) Sessions in ASP.NET Core MVC

Distributed sessions store session data in an external store such as a database, Redis, or SQL Server. Data is not tied to the application’s process, ensuring persistence across restarts and crashes. It is suitable for applications running in a distributed environment (e.g., cloud, load-balanced setups).

Advantages of Distributed (Out-Proc) Sessions:
  • Distributed sessions are Ideal for load-balanced, multi-server, and cloud-based applications that require scalability and run across multiple servers. The session data is stored in a centralized location, accessible to all servers.
  • The session data is preserved even if individual web servers are restarted or the application crashes.
  • It supports various storage backends, such as SQL Server, Redis, and others, which can be chosen based on the application’s specific needs and existing infrastructure.
  • It enables sharing session data across different servers.
Disadvantages of Distributed (Out-Proc) Sessions:
  • Requires additional configuration and infrastructure setup, such as maintaining a Redis cache or SQL database for session storage.
  • Depending on the storage mechanism and network latency, accessing session data might be slower compared to in-memory sessions.
  • Using external services (like Redis Cache) or maintaining dedicated infrastructure for session storage can increase costs.
Choosing Between In-Memory and Distributed Sessions in ASP.NET Core MVC
  • Single Server Environment: Use In-Memory sessions for simplicity and performance.
  • Load-Balanced or Cloud Environment: Use Distributed sessions for scalability and reliability.
  • Persistence Requirement: Use Distributed sessions if session data needs to persist across application restarts.
  • Resource Constraints: Use In-Memory sessions if external dependencies are not feasible.

In the next article, I will explain the Differences Between Cookies and Sessions in ASP.NET Core MVC with Examples. In this article, I try to explain In-Memory or In-Proc and Distributed or Out-Proc Sessions in ASP.NET Core MVC with Examples. I hope you enjoy this article in the In-Memory or In-Proc and Distributed or Out-Proc Sessions in ASP.NET Core MVC.

Leave a Reply

Your email address will not be published. Required fields are marked *