How Sessions works internally in ASP.net core

Http requests are stateless, sessions are used to maintain/persist data between http requests, it’s one of many approaches used in asp.net for state management.

In this post, I will explain how and where the session data are stored, how the data is secured, managed and retrieved.

I will not talk about how to add and configure sessions in asp.net core, this already well explained in Microsoft website here : https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-5.0#session-state, but I will explain how the session managed internally.

First, to enable the session in asp.net core application we have to add the session middleware with its options

services.AddSession(opt => {
    opt.Cookie.HttpOnly = true;
    opt.Cookie.IsEssential = true;
    opt.Cookie.Name = "mySession";
    opt.IdleTimeout = TimeSpan.FromMinutes(60);  });

The middleware will do the following :
1) it will try to get the current Session Key that is stored in the cookies using the cookie name, the default cookie name is ‘.AspNetCore.Session’ but this name can be changed using the session options as in the code above I have changed the cookie name to “mySession”.

2) if the cookie is not set yet, let say we run the application for the first time, the application will create the cookie and set a value to this cookie that value is the session key(don’t mix this key with the key used when we set the session values ), this key is Guid value protected by ‘IDataProtectionProvider’, so for example if the generated Guid is ‘913bb0db-db8e-e4f4-20f2-09105cbdd9b4’ the protected Session Key will be like this:
CfDJ8Jr125GqIuptAtiBVRfZm92ruBUEtCKr5IQwQMKwjE2mb0HHUIJwtKVFpE5STNl0/c9evRq6MiemCxfiItasbUbvXF3eQyO++O0OtAJ4jMJ6cvH/NAWIcflPIYvoV8OQup3kteaFmxnZTOB4B+bvvCaIYnOhcPoI6mO0gYz5YfQ47

This is a protected Session Key will be the cookie value that will be stored in the client browser, this key will be used to set and retrieve data from session storage.

3) After setting the cookie value, the middleware will create the session object, which means it will use the session storage provided by the application to decide where we will store the session data, Microsoft provide a default implementation of IDistributedCache that stores session items in memory, the default implementation in MemoryDistributedCache class, we can add this default implementation to the application as storage for the session items like this :

services.AddDistributedMemoryCache();

This will allow storing the data in the machine memory where the application is running and don’t let the name fools you, this storage is not distributed as the name implies, if you have an application that runs on multiple machines you have to use another session storage that really distributed like Redis.

After creating the session object, the middleware will attach this object to the HttpContext.

 var feature = new SessionFeature();
            feature.Session = _sessionStore.Create(sessionKey, _options.IdleTimeout, _options.IOTimeout, tryEstablishSession, isNewSessionKey);
            context.Features.Set<ISessionFeature>(feature);

4) Session data represented in (key, value) pair and will be first stored in a Dictionary structure managed by DefaultDistributedSessionStore class as a temporary storage, during the http request, any manipulation to the session data will be done in that dictionary, then before sending the response to the user the dictionary with its data will be serialized to byte arrays and then stored in-memory cache with the session key(the key we got from the cookies) and that’s how we persist the data between requests, this key will indicate where the data stored in memory cache.

For example, setting session data

  HttpContext.Session.SetString("test_session", "random value");

The session object is now part of HttpContext, when calling SetString which is an extension of ISession, that method wraps the Set method of the ISession, it will convert the string to byte value and use the ISession set method to store the byte values to the dictionary as the following:

 public static void SetString(this ISession session, string key, string value)
        {
            session.Set(key, Encoding.UTF8.GetBytes(value));
        }

session.Set will just add the value to dictionary if we call session.Set multiple times or removed other values during the same request (before sending back the response )it will be added and deleted from the dictionary and will not be written to the cache memory until the end of the request, this will improve performance because it’s easier and faster to manipulate the data in the dictionary than the cache memory.

on the other hand, reading the data from the session is almost the same, first, the session data will be loaded from the cache memory using the session key (the session key that we obtained from the cookie not the key we used to set the session value), the loaded data will be stored back to the dictionary and then using the key(the same key we used to set the value in this case “test session” in the example above) to get the value of the session from the dictionary.

The implementation of the getting the value is the following :

 public bool TryGetValue(string key, [NotNullWhen(true)] out byte[]? value)
        {
            Load();
            return _store.TryGetValue(new EncodedKey(key), out value);
        }

Notice the Load(), method, this will load the data from the cache memory, desterilize it and store it back to the dictionary then we can use this dictionary to get and set session values and once we done and we are ready to send the response the dictionary it will be serialized and written back to the cache memory, if the dictionary didn’t change (we didn’t set of removed any data) then there is no need to write back the dictionary.

There is another load method for async operation, LoadAsync(); if we want to load the session asynchronously we have to call the method explicitly before calling the TryGetValue.

For other types of storage, the process is the same the only different is where the session data will be stored for example if we used SqlServerCache.cs implementation the data will be stored in the database, this kind of storage is useful if we have a web app running on multiple machines, storing the session in separated database will enable all the machines to share the same session value, however, it’s better to use Redis instead of sql server database for better performance.



Advertisement

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s