Управление состоянием в ASP.NET Core. Сессии

Хранение данных пользователя с использованием сессий — это более сложный вариант работы по управлению состоянием в ASP.NET Core, чем куки или использование HttpContext.items, но, вместе с этим, и более гибкий в плане возможностей вариант.

Сессия в ASP.NET Core

Сессия — это ряд последовательных запросов, совершенных пользователем в браузере в течение некоторого времени. Сессии в ASP.NET Core могут использоваться для хранения временных данных, которые должны быть доступны, пока пользователь работает с приложением.

Для хранения состоянии сессии в ASP.NET Core используется следующая схема работы:

  1. На сервер создается словарь или хэш-таблица, которая размещается в кэше и сохраняется для каждого браузера. Эта таблица хранится до тех пор, пока живёт сессия.
  2. На клиент отправляется идентификатор сессии. Для этого используются куки.
  3. В каждом запросе пользователя возвращается кука с идентификатором сессии. По этому идентификатору из кэша получаются необходимые данные.
  4. Куки удаляются при завершении сессии. Если сервер получает куки, установленные для истекшей сессии, то для этих cookies создается новая сессия.

Сервер хранит данные сессии в течение ограниченного промежутка времени после последнего запроса. По умолчанию этот промежуток равен 20 минутам при необходимости этот промежуток времени можно изменить.

Использование сессий в ASP.NET Core

Чтобы использовать в приложении ASP.NET Core сессии нам необходимо:

  1. Подключить любой сервис кэширования — любой сервис кэширования, реализующий интерфейс  IDistributedCache 
  2. Подключить сервис для работы с сессиями (вызвать AddSession())
  3. Встроить в конвейер обработки запросов компонент middleware для поддержки сессий (вызвать метод UseSession())

Реализуем этот порядок работы в приложении:

namespace AspNetSessions
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            builder.Services.AddDistributedMemoryCache();//подключаем кэш
            builder.Services.AddSession(); //добавляем сервис работы с сессиями

            var app = builder.Build();

            app.UseSession(); //включаем middleware

            app.Run(async (context)=>
            {
                if (context.Session.IsAvailable)
                {
                    if (context.Session.Keys.Contains("session_string"))
                    {
                        var data = context.Session.GetString("session_string");
                        await context.Response.WriteAsync(data);
                    }
                    else
                    {
                        context.Session.SetString("session_string", "Hello session");
                        await context.Response.WriteAsync("Hello, world");
                    }
                }
            });
            app.Run();
        }
    }
}

В приведенном выше примере реализованы все шаги по использованию сессий в ASP.NET Core:

подключение необходимых сервисов

builder.Services.AddDistributedMemoryCache();//подключаем кэш 
builder.Services.AddSession(); //добавляем сервис работы с сессиями

подключили компонент middleware:

app.UseSession(); //включаем middleware

и только после этого начали работать с данными сессии:

app.Run(async (context)=>
{
    if (context.Session.IsAvailable)
    {
        if (context.Session.Keys.Contains("session_string"))
        {
            var data = context.Session.GetString("session_string");
            await context.Response.WriteAsync(data);
        }
        else
        {
            context.Session.SetString("session_string", "Hello session");
            await context.Response.WriteAsync("Hello, world");
        }
    }
});

здесь мы проверяем наличие ключа в кэше session_string и в зависимости от результата проверки любо добавляем новую строку в кэш:

context.Session.SetString("session_string", "Hello session");

либо выводим значение пользователю:

var data = context.Session.GetString("session_string"); 
await context.Response.WriteAsync(data);

Как и в случае работы с куками, при первом запуске приложение не обнаружит ничего в кэше, поэтому необходимо будет обновить страницу в браузере. Чтобы убедиться в том, что сессия работает, можно заглянуть в инструменты разработчика в браузере и убедиться, что кука с идентификатором сессии используется в запросах:

Свойство context.Session представляет собой объект, реализующий интерфейс ISession. Посмотрим на свойства и методы этого интерфейса

Интерфейс ISession

Свойства

Id уникальный идентификатор текущего сессии.
IsAvailable указывает, успешно ли загружен текущая сессия.
Keys список всех ключей для текущей сессии.

Методы

Clear() очищает сессию.
CommitAsync() сохраняет сессию в хранилище данных.
LoadAsync() загружает сессию из хранилища данных.
Remove() удаляет значение по указанному ключу
Set() устанавливает по ключу значение, которое представляет массив байтов
TryGetValue() получает значение в виде массива байтов по заданному ключу, если оно имеется.

Методы расширения

Get() возвращает значение массива байтов из ISession.
GetInt32() возвращает значение типа int из ISession.
GetString() возвращает строковое значение из ISession.
SetInt32() задает значение int в ISession.
SetString() задает String значение в ISession.

 

Как можно увидеть, в данных сессии мы можем хранить три типа значений — массивы байтов, целочисленные значения и строки. Однако, это не означает, что мы не можем записать в данные сессии, например, какой-то сложный объект. Всё, что для этого необходимо — это сериализовать объект, например,в JSON. Чтобы немного упростить себе работу в дальнейшем, можно написать два метода расширения для ISession:

public static class SessionExtensions
{
    public static void SetJsonObject<T>(this ISession session, string key, T obj)
    {
        session.SetString(key, JsonSerializer.Serialize<T>(obj));
    }

    public static T? GetJsonObject<T>(this ISession session, string key)
    {
        if (session.Keys.Contains(key))
            return JsonSerializer.Deserialize<T>(session.GetString(key));
        else
            return default;
    }
}

Первый метод записывает объект в формате Json, второй — десериализует JSON в заданный объект. Эти методы расширения можно использовать, например, так:

public class Test
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddDistributedMemoryCache();//подключаем кэш
        builder.Services.AddSession(); //добавляем сервис работы с сессиями

        var app = builder.Build();

        app.UseSession(); //включаем middleware

        app.Run(async (context) =>
        {
            if (context.Session.Keys.Contains("json"))
            {
                var data = context.Session.GetJsonObject<Test>("json");
                await context.Response.WriteAsJsonAsync(data);
            }
            else
            {
                Test test = new Test()
                {
                    Id = 1,
                    Description = "test",
                    Name = "test"
                };
                context.Session.SetJsonObject<Test>("json", test);
                await context.Response.WriteAsync("Hello, world");
            }

        });
        app.Run();
    }
}

Результат работы приложения:

первый запрос

второй запрос

Итого

Хранение данных пользователя с использованием сессий позволяет задействовать в работе сервера кэш и сохранять не только строки и целочисленные значения, но и сложные объекты, используя сериализацию в JSON.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии