Configure SQL Server Session State In ASP.NET Core

Introduction
 
Session is a feature in ASP.NET Core that enables us to save/store user data. Session stores the data in a dictionary on the Server and SessionId is used as a key. The SessionId is stored on the client at the cookie. The SessionId cookie is sent with every request. The SessionId cookie is Browser specific  and it cannot be shared among the Browsers. There is no timeout specified for SessionId cookie and they are deleted when the Browser session ends.

Session are of two types: InProc or In-memory and OutProc or Distributed session. If our session is in-memory and our Application is hosted on Web-Farm environment, we need to use sticky sessions to tie each session to a specific server. Whereas OutProc session does not require sticky sessions and they are the most preferred way to use session in our application.

In my previous article, I talked about InProc or In-memory session. In this article, we will learn about OutProc - SQL Server Session state in ASP.NET Core. 
 
Configure SQL Server session state
 
In SQL Server Session state, previous version of ASP.NET requires a number of tables and stored procedures to manage the storage of session in SQL server and this can be configured, using “aspnet_regsql” command or a tool. ASP.NET Core requires only one table. There are multiple ways to generate this storage table. The first is to use "Microsoft.Extensions.Caching.SqlConfig.Tools" tool. Before we run the commands of these tools, we need to install this tool. To install this tool, we need to add this tool in project.json and perform "dotnet restore" command. 
 
Project.json
  1.  "tools": {  
  2.       "Microsoft.Extensions.Caching.SqlConfig.Tools""1.0.0-preview2-final"   
  3. }  
Once this tool is installed for our project, we can execute "sql-cache" command, which generates the required table and an index. The command is in the format given below. 
  1. dotnet sql-cache create <connection string>  <schema>  <table name>  
Here, I am using SQL Express edition and following becomes full command, which generates the table and an index.
  1. dotnet sql-cache create "Data Source=.\SQLExpress;Initial Catalog=Test;Integrated Security=True;" "dbo" "SQLSessions"  
 
 
 
 
Alternatively, we can create this table and an index manually. The script is given below to create a table and an index. 
  1. CREATE TABLE [dbo].[SQLSessions](  
  2.     [Id] [nvarchar](449) NOT NULL,  
  3.     [Value] [varbinary](maxNOT NULL,  
  4.     [ExpiresAtTime] [datetimeoffset](7) NOT NULL,  
  5.     [SlidingExpirationInSeconds] [bigintNULL,  
  6.     [AbsoluteExpiration] [datetimeoffset](7) NULL,  
  7.  CONSTRAINT [pk_Id] PRIMARY KEY CLUSTERED   
  8. (  
  9.     [Id] ASC  
  10. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  11. ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]  
  12.   
  13. GO  
  14. CREATE NONCLUSTERED INDEX [Index_ExpiresAtTime] ON [dbo].[SQLSessions]  
  15. (  
  16.     [ExpiresAtTime] ASC  
  17. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)  
  18. GO  
SQL session state internally uses memory cache, so as to enable SQL Server session. We need to add "Microsoft.Extensions.Caching.SqlServer" dependency along with "Microsoft.AspNet.Session" into project.json file.
 
project.json
  1. {  
  2.   "version""1.0.0-*",  
  3.   "buildOptions": {  
  4.     "preserveCompilationContext"true,  
  5.     "debugType""portable",  
  6.     "emitEntryPoint"true  
  7.   },  
  8.   "tools": {  
  9.       "Microsoft.Extensions.Caching.SqlConfig.Tools""1.0.0-preview2-final"   
  10.   },  
  11.   "dependencies": {},  
  12.   "frameworks": {  
  13.     "netcoreapp1.0": {  
  14.       "dependencies": {  
  15.         "Microsoft.NETCore.App": {  
  16.           "type""platform",  
  17.           "version""1.0.1"  
  18.         },  
  19.     "Microsoft.AspNetCore.Server.Kestrel""1.0.0",  
  20.     "Microsoft.AspNetCore.Mvc""1.0.0",  
  21.     "Microsoft.AspNetCore.Session" : "1.0.0",  
  22.     "Microsoft.Extensions.Caching.SqlServer" : "1.0.0",  
  23.     "Microsoft.Extensions.Configuration.Json" : "1.0.0"  
  24.       },  
  25.       "imports""dnxcore50"  
  26.     }  
  27.   }  
  28. }  
We can add a connection string to appSetting.json file or put it directly in ConfigureServices method of startup class. Following is the definition of ConfigureServices and Configure method of startup class. 
 
Startup.cs
  1. using System;  
  2. using Microsoft.AspNetCore.Builder;  
  3. using Microsoft.AspNetCore.Http;  
  4. using Microsoft.Extensions.DependencyInjection;  
  5.   
  6. namespace WebApplication {  
  7.     public class Startup{  
  8.         public void ConfigureServices(IServiceCollection services)  
  9.         {  
  10.             services.AddDistributedSqlServerCache(options =>  
  11.             {  
  12.                 options.ConnectionString = @"Data Source=.\SQLExpress;Initial Catalog=Test;Integrated Security=True;";  
  13.                 options.SchemaName = "dbo";  
  14.                 options.TableName = "SQLSessions";  
  15.             });  
  16.               
  17.             services.AddSession(options => {   
  18.                 options.CookieName = "Test.Session";  
  19.                 options.IdleTimeout = TimeSpan.FromMinutes(60);   
  20.             });  
  21.               
  22.               
  23.             services.AddMvc();  
  24.         }  
  25.         public void Configure(IApplicationBuilder app){  
  26.             app.UseSession();  
  27.             app.UseMvc();              
  28.             app.Run(context => {  
  29.                 return context.Response.WriteAsync("Hello Readers!");  
  30.             });   
  31.         }  
  32.     }  
  33. }  
Example

In the example given below, I have set my name into session in the first request and retrieved the session value in another request. 
  1. using Microsoft.AspNetCore.Http;  
  2. using Microsoft.AspNetCore.Mvc;  
  3. using Microsoft.Extensions.Caching.Distributed;  
  4.   
  5. public class HomeController : Controller  
  6. {  
  7.     [Route("home/index")]  
  8.     public IActionResult Index()  
  9.     {  
  10.         HttpContext.Session.SetString("name","Jignesh Trivedi");  
  11.         return View();  
  12.     }  
  13.     [Route("home/GetSessionData")]  
  14.     public IActionResult GetSessionData()  
  15.     {  
  16.         ViewBag.data = HttpContext.Session.GetString("name");  
  17.         return View();  
  18.     }  
  19. }  
Output

 
With SQL server state in ASP.NET Core, we can also create and use the session extension methods and we can also store complex objects in to the session.

Summary
 
This article described the steps required to enable SQL Server as a storage mechanism for session state in an ASP.NET Core MVC Application. The usage of SQL server session state is slightly different than the classic ASP.NET Application.