Chapter 14
Session State Design Patterns
Introduction
In order to organize the session state, the design patterns of this category can be divided into the following three main sections:
Client session state: Information about the user session is stored on the client side.
Server session state: Information about the user session is stored on the server side.
Database session state: Information about the session is stored in the database.
Structure
In this chapter, we will discuss the following topics:
Session state design patterns
Client session state
Server session state
Database session state
Objectives
In this chapter, you will learn the differences between stateless and stateful software. You will learn the different session maintenance and management methods, how to save the session on the client or server-side or even the database, and each method's differences, advantages, and disadvantages.
Session state design patterns
When we talk about transactions, we often talk about system and business transactions, and this continues into the discussion of stateless or stateful sessions. But first, it should be determined what is meant by stateful or stateless.
When we look at an object, this object consists of a series of data (status) and behaviors. In enterprise software, stateless means a state where the server does not keep the data between two requests. We will face stateful mode if the server needs to store data between two requests.
There are several considerations for dealing with the stateful method. Sometimes we need to store the data during a series of specific sessions. In this case, this data is the session state. Since the session state is often inside the business transaction, then the attributes proposed for the transaction will also be true for the session state.
The important thing about session states is how they are stored. If we want to store data on the client side, then using the client session state design pattern can be useful. The server session state design pattern will be a good option for storing the data in the server memory. The database session state design pattern will be more suitable if we want to store the data in the database.
If we face many users, we will need methods such as clustering to improve throughput. In this case, paying attention to session migration will often be necessary. For session migration, one request may be processed on server A and the next request, which is a continuation of the previous request, may be processed on server B. The opposite of this method will be session affinity. In this method, a server will be responsible for processing all requests for a specific session.
Client session state
Name:
Client session state
Classification:
Session state design patterns
Also known as:
---
Intent:
Using this design pattern, the information related to the user's session is stored on the client side.
Motivation, Structure, Implementation, and Sample code:
Let us suppose that a requirement has been raised, and it is necessary to implement the possibility of video sharing on the website. To implement this requirement, there are various methods, but what is important in this requirement is the possibility of video sharing. The easiest way to share videos on the web is to share via URL. For example, pay attention to the following URL:
http://jinget.ir/videos?id=1
The preceding address consists of several different parts, which are:
Exchange protocol: In the preceding address, it is the same as http
Domain name: jinget.ir in the preceding address.
Path: There are videos at the preceding address
Query parameters: id=1 in the preceding address
With the help of the preceding address, by sending a GET request, you can inform the server that we intend to receive the video with id equal to 1. In this type of connection, the server does not need to keep any information about the request; all the necessary information is stored on the client side. This method is one of the methods the client session state design pattern tries to provide. Suppose the user changes the preceding address and sends the parameter id=2 instead of id=1. Since the server has not saved any information about the user's session, it will process the request and return the video with an Id equal to 2 in response. Therefore, one of the problems of using this method will be its security.
One of the ways to connect the user’s session to the client and the server is to return the session's id to the client in the form of a URL. When the client sends its request to the server by providing the session ID, it helps the server to find the complete information of the previous session related to the given session ID. Often, in order to reduce the probability of estimating and guessing the session ID, this ID is generated as a random string. For example, consider the following URL:
http://jinget.ir/sessionId=ahy32hk
In the preceding URL, the value of ahy32hk is a random value for the sessionId. By providing it to the server, the client can cause the corresponding session to be found on the server and the information processed.
To protect security, suppose we want to send information related to the user's identity as a request. Usually, this information includes a token with long string content. The next problem in using this method is the limitation of the length of the address. Therefore, we need to either go for other methods or combine the preceding method with other methods. Another method is using the hidden field to save the session information on the user's side. Hidden fields in HTML can be defined as follows:
Hidden fields are uncommon nowadays, but this method allows for storing and sending more information to the server. Following the preceding requirement, we can get the user's identity information from the server and save it as a string in the hidden field. The important feature of a hidden field is that it is placed on the page as an HTML element but not displayed to the user. This does not mean that the user does not have access to its value, and the user can view the content stored in the hidden field by referring to the source of the HTML page.
Users can change this content and face the security threat when they see it. For this purpose, encryption methods can be used. The drawback of using encryption will be that it will disrupt the application's overall performance because each request and response will need to be encrypted and decrypted before and after processing.
The advantage of this method is that you can send any type of request to the server, and it is not limited to GET requests like the URL method. For example, the DTO received from the server can be serialized in XML or JSON format and stored in the hidden field. The important problem in using this method is that today, with the expansion of web service and Web API, the client does not necessarily include HTML codes that can store session information in them.
There is also a third method to solve the problem related to hidden fields, and that is to use cookies. The use of cookies has always been controversial and has its supporters and opponents. One of the most important problems with cookies is that cookies may be disabled in the user's browser. In this case, the program's performance will face problems, so when entering most websites that use cookies, the user is asked to allow the website to use cookies.
For example, in the following code, sessionState is set inside the web.config file. As this code snippet shows, the session state uses an id cookie to identify client sessions. Therefore, in every request and response, this cookie is transferred between the user and the server.
The important thing about the cookie is that the information included in the cookie is sent to the server with every request and returned to the client in the server's response. Like the URL method, cookies also have a size limit, which can be an important problem. Also, cookies, like hidden fields, have the problem that the user can see or change their content. Cookies provide more important features than hidden fields. For example, cookies can be set to only be read on the server side, and client codes do not have access to cookie values.
Notes:
Regardless of what design pattern is used to maintain the session or its information, this design pattern is required to communicate between the request on the client side with the related processing and the response on the server side.
An object is generated on the server side and stored in memory. A key is needed to identify this object, and we call this key SessionId. The response sent to the client contains this SessionId. Hence, the client, in the return request to the server by presenting the SessionId causes the object related to them to be identified among the many objects.
Regardless of which method is used to store and send session information to the server, the received information must be validated from the beginning whenever a request is sent.
Consequences: Advantages
To have a stateless server, using this design pattern is very useful. The stateless nature of the server makes it possible to implement clustering methods on the server side with the lowest cost.
Consequences: Disadvantages
This design pattern is always influenced by the amount of data we want to store. Usually, for a large volume of data, the location and method of data storage on the client side will be an important problem.
Since data is stored on the client side, security threats are important in this design pattern.
Applicability:
This design pattern can be used to implement the server in stateless mode.
Related patterns:
Some of the following design patterns are not related to the client session state design pattern, but to implement this design pattern, checking the following design patterns will be useful:
Server session state
Database session state
Server session state
Name:
Server session state
Classification:
Session state design patterns
Also known as:
---
Intent:
Using this design pattern, the information related to the user session is stored on the server side.
Motivation, Structure, Implementation, and Sample code:
In the example provided for the client session state design pattern, suppose we want to store information about the session on the server side. In this case, an object is generated on the server side for each session.
By default, this object is stored in the memory, and SessionId is used to refer to that object and find it among the many objects related to different sessions. SessionId is key to finding information about the session. This key must be provided to the client in some way, and in the next request that the client sends to the server, by providing the SessionId to the server, the information related to their session will be found, and the processing and response generation operations will be done. Figure 14.1 shows the overall process of the server session state design pattern:
Figure14.1.png
Figure 14.1 Server Session State
The problem with the preceding scenario is that with the increase in the number of users or the increase in the number of sessions, the number of objects in the memory will increase, and this will cause a significant amount of server memory to be allocated to store these objects. In addition to increasing the amount of memory consumption on the server side, the possibility of clustering and implementing load-balancing methods will also be difficult.
The session status can be serialized and stored in a data source using the memento design pattern to solve this problem. In this case, choosing the serial format will be important. As mentioned, data can be serialized and stored in string or binary formats. This will make the server stateful while providing clustering, load balancing, and so on the server side. This method will affect the overall performance of the program.
The location of the data source will be important in the preceding method. You can consider the data source on the same application server or use a separate server to store this information. It is evident that if these data are stored on the same server application, the flexibility will be reduced in front of the design and implementation of clustering solutions, and so on.
To implement this design pattern, suppose we need to use an In-Memory session provider, so we need to install Microsoft.AspNetCore.Session package to enable the use of session middleware. Run the following command to install this package:
dotnet add package Microsoft. AspNetCore.Session
Note that you can use different methods to install NuGet packages. For example, you can use package manager CLI as follows:
NuGet\Install-Package Microsoft.AspNetCore.Session
For more information about this NuGet package, please refer to the following link: https://www.nuget.org/packages/Microsoft.AspNetCore.Session
After installing this package, we need to configure the use of the session as follows in Program.cs file:
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.Cookie.Name = "SessionInfo";
options.IdleTimeout = TimeSpan.FromMinutes(60);
});
In the preceding code, it is mentioned that an in-memory provider is going to be used. Also, it is stated that the session ID will be stored in the SessionInfo cookie in the client’s browser so that with each server request, this cookie will be sent to the server too. By providing this cookie to the server, the server will be able to find the client-related session and loads its data.
The IdleTimeout indicates how long the session can be idle before its contents are abandoned. Each session access resets the timeout, and note this only applies to the content of the session, not the cookie.
Finally, call the app.UseSession() adds the SessionMiddleware to enable the session state for the application automatically. After configuring the preceding settings, Program.cs file should look as follow:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.Cookie.Name = "SessionInfo";
options.IdleTimeout = TimeSpan.FromMinutes(60);
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.UseSession();
app.Run();
When the client loads the application, a cookie will be created in the client’s browser, which will be used to find the session data related to the specific client. Figure 14.2 shows this cookie (SessionInfo cookie):
Figure14.2.png
Figure 14.2: Cookie created in the client browser
Now we can set the value to the session object as follows:
public IActionResult Index()
{
HttpContext.Session.SetString("Name", "Vahid Farahmandian");
HttpContext.Session.SetString("TimeStamp", DateTime.Now.ToString());
return View();
}
And get the value from the session object as follow:
public IActionResult Privacy()
{
ViewBag.data = HttpContext.Session.GetString("Name") +
HttpContext.Session.GetString("TimeStamp");
return View();
}
If we navigate the browser to the Index view, values will be set in the session object, and when we navigate to the Privacy view, we can see the values stored in the session object.
If we host the application in IIS, when we restart the application pool, all the data related to the session will be abandoned because the session information is stored in the server’s memory. The memory will be freed up by restarting the application pool.
Notes:
To store session information, you can use Serialized LOB design pattern.
Consequences: Advantages
The implementation and use of this design pattern is very simple.
Consequences: Disadvantages
It is difficult to implement solutions to improve efficiency, including clustering.
Applicability:
This design pattern can be used to implement the server in stateful mode.
Related patterns:
Some of the following design patterns are not related to the server session state design pattern, but to implement this design pattern, checking the following design patterns will be useful:
Client session state
Database session state
Memento
Serialized lob
Database session state
Name:
Database session state
Classification:
Session state design patterns
Also known as:
---
Intent:
This design pattern stores information about the session in the database.
Motivation, Structure, Implementation, and Sample code:
The database session state design pattern is similar to the server session state design pattern. The difference is that when the SessionId is sent from the client to the server, the server refers to the database and reads the information related to the SessionId from the database by providing this SessionId to the database. Any changes that occur to this information must be rewritten in the database.
Figure 14.3 shows the overall process of the Database Session State design pattern:
Figure14.3.png
Figure 14.3: Database Session State
When the session is closed, the information related to the session should also be deleted. Usually, SessionId is the primary key in the table where session information is stored, and SessionId can be used to delete a closed session. Sometimes the closing of the session may not be accompanied by a notification. In this case, by considering a timeout for the sessions, the sessions table can be referred to in certain time intervals, and the sessions whose timeout has reached can be deleted.
Suppose that we want to implement the mechanism of saving the session in the database using Microsoft SQL Server and ASP.NET Core.
Note that implementing this design pattern in ASP.NET Core differs from ASP.NET. For example, to implement this design pattern in ASP.NET, it was necessary to create several tables and procedures in the database using the aspnet_regsql command or tool, but in ASP.NET Core, these tables and stored procedures are no longer needed, and the design pattern can be implemented with just one table.
There are different ways to create this table, including using the NuGet package called Microsoft.Extensions.Caching.SqlConfig.Tools, or you can create the table manually and directly in the SQL Server.
According to the preceding explanations, to implement this design pattern in .NET, the following steps can be taken to create a table by using the NuGet package, run the following command to install the package:
dotnet add package Microsoft.Extensions.Caching.SqlConfig.Tools
Note that you can use different methods to install NuGet packages. For example, you can use Package Manager CLI as the following:
NuGet\Install-Package Microsoft.Extensions.Caching.SqlConfig.Tools
For more information about this NuGet package, please refer to the following link: https://www.nuget.org/packages/Microsoft.Extensions.Caching.SqlConfig.Tools
When the package is installed successfully, run the following command to create the corresponding table in the database:
dotnet sql-cache create