Состояние сеанса и приложения в ASP.NET CoreSession and app state in ASP.NET Core

Авторы: Рик Андерсон (Rick Anderson), Стив Смит (Steve Smith), Диана Лароуз (Diana LaRose) и Люк Лэтэм (Luke Latham)By Rick Anderson, Steve Smith, Diana LaRose, and Luke Latham

HTTP — это протокол без отслеживания состояния.HTTP is a stateless protocol. Без дополнительных действий HTTP-запросы являются независимыми сообщениями, которые не сохраняют значения пользователя или состояние приложения.Without taking additional steps, HTTP requests are independent messages that don't retain user values or app state. В этой статье описывается несколько подходов для сохранения данных пользователя и состояния приложения между запросами.This article describes several approaches to preserve user data and app state between requests.

Просмотреть или скачать образец кода (как скачивать)View or download sample code (how to download)

Управление состояниемState management

Состояние можно сохранить несколькими способами.State can be stored using several approaches. Эти способы обсуждается ниже в данном разделе.Each approach is described later in this topic.

Способ хранения данныхStorage approach Механизм храненияStorage mechanism
Файлы "cookie"Cookies Файлы cookie HTTP (могут содержать данные, сохраненные с помощью кода приложения на стороне сервера)HTTP cookies (may include data stored using server-side app code)
Состояние сеансаSession state Файлы cookie HTTP и код приложения на стороне сервераHTTP cookies and server-side app code
TempDataTempData Файлы cookie HTTP или состояние сеансаHTTP cookies or session state
Строки запросовQuery strings Строки запросов HTTPHTTP query strings
Скрытые поляHidden fields Поля формы HTTPHTTP form fields
HttpContext.ItemsHttpContext.Items Код приложения на стороне сервераServer-side app code
КэшCache Код приложения на стороне сервераServer-side app code
Введение зависимостейDependency Injection Код приложения на стороне сервераServer-side app code

Файлы cookieCookies

Файлы cookie хранят данные между запросами.Cookies store data across requests. Так как файлы cookie отправляются с каждым запросом, их размер нужно свести к минимуму.Because cookies are sent with every request, their size should be kept to a minimum. В идеальном случае файл cookie должен содержать лишь идентификатор, а сами данные хранятся в приложении.Ideally, only an identifier should be stored in a cookie with the data stored by the app. Большинство браузеров позволяют использовать файлы cookie размером до 4096 байт.Most browsers restrict cookie size to 4096 bytes. Для каждого домена доступно лишь ограниченное число файлов cookie.Only a limited number of cookies are available for each domain.

Так как файлы cookie могут быть незаконно изменены, их нужно проверять в приложении.Because cookies are subject to tampering, they must be validated by the app. Файлы cookie могут удаляться пользователем и имеют ограниченный срок хранения на клиентах.Cookies can be deleted by users and expire on clients. Тем не менее файлы cookie обычно являются самым надежным способом хранения данных на стороне клиента.However, cookies are generally the most durable form of data persistence on the client.

Файлы cookie часто используются для персонализации, когда содержимое настраивается под известного пользователя.Cookies are often used for personalization, where content is customized for a known user. В большинстве случаев пользователь проходит только идентификацию, а не проверку подлинности.The user is only identified and not authenticated in most cases. Файл cookie может хранить имя пользователя, имя учетной записи или уникальный идентификатор пользователя (например, GUID).The cookie can store the user's name, account name, or unique user ID (such as a GUID). Затем можно использовать файл cookie для доступа к личным настройкам пользователя, таким как цвет фона на веб-сайте.You can then use the cookie to access the user's personalized settings, such as their preferred website background color.

Помните об Общем регламенте по защите данных в ЕС (GDPR) при создании файлов cookie и решении вопросов с конфиденциальностью.Be mindful of the European Union General Data Protection Regulations (GDPR) when issuing cookies and dealing with privacy concerns. Дополнительные сведения см. в разделе Общий регламент по защите данных (GDPR), принятый в ЕС, в ASP.NET Core.For more information, see General Data Protection Regulation (GDPR) support in ASP.NET Core.

Состояние сеансаSession state

Состояние сеанса — это сценарий ASP.NET Core для хранения пользовательских данных, когда пользователь находится в веб-приложении.Session state is an ASP.NET Core scenario for storage of user data while the user browses a web app. Состояние сеанса использует хранилище, обслуживаемое приложением, для сохранения данных между запросами от клиента.Session state uses a store maintained by the app to persist data across requests from a client. Данные сеанса поддерживаются кэшем и считаются временными, — сайт должен работать и без данных сеанса.The session data is backed by a cache and considered ephemeral data—the site should continue to function without the session data. Критически важные данные приложения должны храниться в пользовательской базе данных и кэшироваться в сеансе только в качестве оптимизации производительности.Critical application data should be stored in the user database and cached in session only as a performance optimization.

Примечание

Сеанс не поддерживается в приложениях SignalR, так как хаб SignalR может выполняться независимо от контекста HTTP.Session isn't supported in SignalR apps because a SignalR Hub may execute independent of an HTTP context. Например, это может произойти, если хаб поддерживает длительный запрос на опрос открытым, когда время существования контекста HTTP для запроса уже истекло.For example, this can occur when a long polling request is held open by a hub beyond the lifetime of the request's HTTP context.

ASP.NET Core сохраняет состояние сеанса, предоставляя клиенту файл cookie, содержащий идентификатор сеанса, который отправляется в приложение вместе с каждым запросом.ASP.NET Core maintains session state by providing a cookie to the client that contains a session ID, which is sent to the app with each request. Приложение использует этот идентификатор для получения данных сеанса.The app uses the session ID to fetch the session data.

Состояние сеанса реагирует на события следующим образом:Session state exhibits the following behaviors:

  • Так как файл cookie сеанса относится к конкретному браузеру, обеспечить общий доступ к сеансам из разных браузеров невозможно.Because the session cookie is specific to the browser, sessions aren't shared across browsers.
  • Файлы cookie сеанса удаляются при завершении сеанса браузера.Session cookies are deleted when the browser session ends.
  • Если получен файл cookie для просроченного сеанса, создается сеанс, использующий этот же файл.If a cookie is received for an expired session, a new session is created that uses the same session cookie.
  • Пустые сеансы не сохраняются — в сеансе должно быть хотя бы одно значение, чтобы его можно быть сохранить между запросами.Empty sessions aren't retained—the session must have at least one value set into it to persist the session across requests. Если сеанс не сохраняется, для каждого нового запроса создается новый идентификатор сеанса.When a session isn't retained, a new session ID is generated for each new request.
  • Приложение хранит сеанс некоторое время после последнего запроса.The app retains a session for a limited time after the last request. Приложение устанавливает время ожидания сеанса или использует значение по умолчанию, равное 20 минутам.The app either sets the session timeout or uses the default value of 20 minutes. Состояние сеанса оптимально подходит для сохранения пользовательских данных, относящихся к определенному сеансу, которые не требуется хранить бессрочно для нескольких сеансов.Session state is ideal for storing user data that's specific to a particular session but where the data doesn't require permanent storage across sessions.
  • Данные сеанса удаляются при вызове реализации ISession.Clear или когда истекает срок действия сеанса.Session data is deleted either when the ISession.Clear implementation is called or when the session expires.
  • Не существует механизма по умолчанию, который бы информировал код приложения о том, что браузер клиента закрыт или файл cookie сеанса удален или просрочен на клиенте.There's no default mechanism to inform app code that a client browser has been closed or when the session cookie is deleted or expired on the client.
  • Шаблоны ASP.NET Core MVC и Razor Pages поддерживают общий регламент по защите данных (GDPR).The ASP.NET Core MVC and Razor pages templates include support for General Data Protection Regulation (GDPR). Файлы cookie для состояния сеанса не помечаются как основные по умолчанию, поэтому состояние сеанса недоступно, если отслеживание разрешено посетителем сайта.Session state cookies aren't marked essential by default, so session state isn't functional unless tracking is permitted by the site visitor. Дополнительные сведения можно найти по адресу: Поддержка Общий регламент по защите данных (GDPR) в ASP.NET Core.For more information, see Поддержка Общий регламент по защите данных (GDPR) в ASP.NET Core.

Предупреждение

Не храните конфиденциальные данные в состоянии сеанса.Don't store sensitive data in session state. Пользователь может не закрывать браузер и очистить файл cookie сеанса.The user might not close the browser and clear the session cookie. Некоторые браузеры сохраняют файлы cookie сеанса в нескольких окнах браузера.Some browsers maintain valid session cookies across browser windows. Сеанс может быть не ограничен одним пользователем — следующий пользователь продолжит использовать приложение с тем же файлом cookie сеанса.A session might not be restricted to a single user—the next user might continue to browse the app with the same session cookie.

Поставщик кэша в памяти хранит данные сеанса в памяти сервера, содержащего приложение.The in-memory cache provider stores session data in the memory of the server where the app resides. В сценарии с фермой серверов:In a server farm scenario:

Настройка состояния сеансаConfigure session state

Пакет Microsoft.AspNetCore.Session, который входит в метапакет Microsoft.AspNetCore.App, предоставляет ПО промежуточного слоя для управления состоянием сеанса.The Microsoft.AspNetCore.Session package, which is included in the Microsoft.AspNetCore.App metapackage, provides middleware for managing session state. Чтобы включить сеанс ПО промежуточного слоя для сеансов, Startup должен содержать:To enable the session middleware, Startup must contain:

Следующий код показывает, как настроить поставщик сеансов в памяти с реализацией в памяти IDistributedCache по умолчанию:The following code shows how to set up the in-memory session provider with a default in-memory implementation of IDistributedCache:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            // Set a short timeout for easy testing.
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
            // Make the session cookie essential
            options.Cookie.IsEssential = true;
        });

        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseSession();
        app.UseHttpContextItemsMiddleware();
        app.UseMvc();
    }
}

Порядок ПО промежуточного слоя важен.The order of middleware is important. В предыдущем примере исключение InvalidOperationException возникает при вызове UseSession после UseMvc.In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc. Дополнительные сведения см. в разделе Порядок расположения ПО промежуточного слоя.For more information, see Middleware Ordering.

После настройки состояния сеанса доступно свойство HttpContext.Session.HttpContext.Session is available after session state is configured.

Невозможно получить доступ к HttpContext.Session до вызова UseSession.HttpContext.Session can't be accessed before UseSession has been called.

Невозможно создать новый сеанс с новым файлом cookie сеанса после того, как приложение начинает запись в поток ответа.A new session with a new session cookie can't be created after the app has begun writing to the response stream. Исключение записывается в журнал веб-сервера и не отображается в браузере.The exception is recorded in the web server log and not displayed in the browser.

Асинхронная загрузка состояния сеансаLoad session state asynchronously

Поставщик сеансов по умолчанию в ASP.NET Core загружает запись сеанса из резервного хранилища IDistributedCache в асинхронном режиме только при явном вызове метода ISession.LoadAsync перед методами TryGetValue, Set или Remove.The default session provider in ASP.NET Core loads session records from the underlying IDistributedCache backing store asynchronously only if the ISession.LoadAsync method is explicitly called before the TryGetValue, Set, or Remove methods. Если LoadAsync не вызывается первым, базовая запись сеанса загружается синхронно, что может негативно повлиять на производительность.If LoadAsync isn't called first, the underlying session record is loaded synchronously, which can incur a performance penalty at scale.

Чтобы принудительно использовать этот режим в приложениях, используйте для реализаций DistributedSessionStore и DistributedSession оболочку из версий, которые выдают исключение, когда метод LoadAsync не вызывается перед TryGetValue, Set или Remove.To have apps enforce this pattern, wrap the DistributedSessionStore and DistributedSession implementations with versions that throw an exception if the LoadAsync method isn't called before TryGetValue, Set, or Remove. Зарегистрируйте версии оболочки в контейнере служб.Register the wrapped versions in the services container.

Параметры сеансаSession options

Чтобы переопределить значения по умолчанию для сеанса, используйте SessionOptions.To override session defaults, use SessionOptions.

ПараметрOption ОПИСАНИЕDescription
Файл cookieCookie Определяет параметры, используемые для создания файлов cookie.Determines the settings used to create the cookie. Параметр Name по умолчанию имеет значение SessionDefaults.CookieName (.AspNetCore.Session).Name defaults to SessionDefaults.CookieName (.AspNetCore.Session). Параметр Path по умолчанию имеет значение SessionDefaults.CookiePath (/).Path defaults to SessionDefaults.CookiePath (/). Параметр SameSite по умолчанию имеет значение SameSiteMode.Lax (1).SameSite defaults to SameSiteMode.Lax (1). Параметр HttpOnly по умолчанию имеет значение true.HttpOnly defaults to true. Параметр IsEssential по умолчанию имеет значение false.IsEssential defaults to false.
IdleTimeoutIdleTimeout IdleTimeout указывает, как долго сеанс может быть неактивным, прежде чем его содержимое отбрасывается.The IdleTimeout indicates how long the session can be idle before its contents are abandoned. Каждый доступ к сеансу сбрасывает время ожидания.Each session access resets the timeout. Этот параметр применяется только к содержимому сеанса, а не к файлу cookie.This setting only applies to the content of the session, not the cookie. Значение по умолчанию — 20 минут.The default is 20 minutes.
IOTimeoutIOTimeout Максимальный период загрузки сеанса из хранилища или его сохранения обратно в хранилище.The maximum amount of time allowed to load a session from the store or to commit it back to the store. Этот параметр может применяться только к асинхронным операциям.This setting may only apply to asynchronous operations. Время ожидания можно отключить с помощью InfiniteTimeSpan.This timeout can be disabled using InfiniteTimeSpan. Значение по умолчанию — 1 минута.The default is 1 minute.

Сеанс использует файл cookie для отслеживания и идентификации запросов в одном браузере.Session uses a cookie to track and identify requests from a single browser. По умолчанию этот файл cookie называется .AspNetCore.Session и использует путь /.By default, this cookie is named .AspNetCore.Session, and it uses a path of /. Так как по умолчанию файл cookie не указывает домен, он остается недоступным для клиентского сценария на странице (так как HttpOnly по умолчанию имеет значение true).Because the cookie default doesn't specify a domain, it isn't made available to the client-side script on the page (because HttpOnly defaults to true).

Чтобы переопределить файл cookie по умолчанию для сеанса, используйте SessionOptions:To override cookie session defaults, use SessionOptions:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDistributedMemoryCache();

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddSession(options =>
    {
        options.Cookie.Name = ".AdventureWorks.Session";
        options.IdleTimeout = TimeSpan.FromSeconds(10);
        options.Cookie.IsEssential = true;
    });
}

Приложение использует свойство IdleTimeout, чтобы определить, как долго сеанс может оставаться неактивным до сброса его содержимого в кэше сервера.The app uses the IdleTimeout property to determine how long a session can be idle before its contents in the server's cache are abandoned. Это свойство не зависит от срока действия файла cookie.This property is independent of the cookie expiration. Каждый запрос, проходящий через ПО промежуточного слоя сеанса, сбрасывает это время ожидания.Each request that passes through the Session Middleware resets the timeout.

Состояние сеанса является неблокирующим.Session state is non-locking. Когда два запроса пытаются изменить содержимое сеанса, последний из них переопределяет первый.If two requests simultaneously attempt to modify the contents of a session, the last request overrides the first. Session реализован в виде согласованного сеанса, что означает, что все содержимое хранится вместе.Session is implemented as a coherent session, which means that all the contents are stored together. Когда два запроса пытаются изменить разные значения сеанса, последний запрос может переопределить изменения, внесенные первым.When two requests seek to modify different session values, the last request may override session changes made by the first.

Установка и получение значений сеансаSet and get Session values

Получить доступ к состоянию сеанса можно через класс Razor Pages PageModel или класс MVC Controller со свойством HttpContext.Session.Session state is accessed from a Razor Pages PageModel class or MVC Controller class with HttpContext.Session. Оно является реализацией ISession.This property is an ISession implementation.

Реализация ISession предоставляет несколько методов расширения для задания и извлечения значений типа integer и string.The ISession implementation provides several extension methods to set and retrieve integer and string values. Методы расширения находятся в пространстве имен Microsoft.AspNetCore.Http (добавьте оператор using Microsoft.AspNetCore.Http;, чтобы получить доступ к методам расширения), когда проект ссылается на пакет Microsoft.AspNetCore.Http.Extensions.The extension methods are in the Microsoft.AspNetCore.Http namespace (add a using Microsoft.AspNetCore.Http; statement to gain access to the extension methods) when the Microsoft.AspNetCore.Http.Extensions package is referenced by the project. Оба пакета входят в метапакет Microsoft.AspNetCore.App.Both packages are included in the Microsoft.AspNetCore.App metapackage.

Методы расширения ISession:ISession extension methods:

В следующем примере извлекается значение сеанса для ключа IndexModel.SessionKeyName (_Name в примере приложения) на странице Razor Pages:The following example retrieves the session value for the IndexModel.SessionKeyName key (_Name in the sample app) in a Razor Pages page:

@page
@using Microsoft.AspNetCore.Http
@model IndexModel

...

Name: @HttpContext.Session.GetString(IndexModel.SessionKeyName)

В следующем примере показано, как задать, а затем получить значения integer и string:The following example shows how to set and get an integer and a string:

public class IndexModel : PageModel
{
    public const string SessionKeyName = "_Name";
    public const string SessionKeyAge = "_Age";
    const string SessionKeyTime = "_Time";

    public string SessionInfo_Name { get; private set; }
    public string SessionInfo_Age { get; private set; }
    public string SessionInfo_CurrentTime { get; private set; }
    public string SessionInfo_SessionTime { get; private set; }
    public string SessionInfo_MiddlewareValue { get; private set; }

    public void OnGet()
    {
        // Requires: using Microsoft.AspNetCore.Http;
        if (string.IsNullOrEmpty(HttpContext.Session.GetString(SessionKeyName)))
        {
            HttpContext.Session.SetString(SessionKeyName, "The Doctor");
            HttpContext.Session.SetInt32(SessionKeyAge, 773);
        }

        var name = HttpContext.Session.GetString(SessionKeyName);
        var age = HttpContext.Session.GetInt32(SessionKeyAge);

Все данные сеанса должны быть сериализованы, чтобы использовать сценарий-распределенного кэша даже при использовании кэша в памяти.All session data must be serialized to enable a distributed cache scenario, even when using the in-memory cache. Предоставляются минимальные сериализаторы строки и числа (см. методы и методы расширения ISession).Minimal string and number serializers are provided (see the methods and extension methods of ISession). Сложные типы должны быть сериализованы пользователем с помощью другого механизма, например JSON.Complex types must be serialized by the user using another mechanism, such as JSON.

Добавьте приведенные ниже методы расширения, чтобы задавать и получать сериализуемые объекты:Add the following extension methods to set and get serializable objects:

public static class SessionExtensions
{
    public static void Set<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonConvert.SerializeObject(value));
    }

    public static T Get<T>(this ISession session, string key)
    {
        var value = session.GetString(key);

        return value == null ? default(T) : 
            JsonConvert.DeserializeObject<T>(value);
    }
}

Следующий пример показывает, как задать и получить сериализуемый объект с помощью методов расширения:The following example shows how to set and get a serializable object with the extension methods:

// Requires you add the Set and Get extension method mentioned in the topic.
if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default(DateTime))
{
    HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}

TempDataTempData

ASP.NET Core предоставляет свойство TempData модели страницы Razor Pages или TempData контроллера MVC.ASP.NET Core exposes the TempData property of a Razor Pages page model or TempData of an MVC controller. Это свойство хранит данные до тех пор, пока они не будут прочитаны.This property stores data until it's read. Для проверки данных без удаления можно использовать методы Keep и Peek.The Keep and Peek methods can be used to examine the data without deletion. TempData особенно удобно использовать для перенаправления, когда данные требуются больше чем для одного запроса.TempData is particularly useful for redirection when data is required for more than a single request. TempData реализуется поставщиками TempData, например с помощью файлов cookie или состояния сеанса.TempData is implemented by TempData providers using either cookies or session state.

Поставщики TempDataTempData providers

Поставщик TempData, основанный на файлах cookie, используется по умолчанию для хранения TempData в файлах cookie.The cookie-based TempData provider is used by default to store TempData in cookies.

Данные в файле cookie шифруются с помощью IDataProtector, кодируются с помощью Base64UrlTextEncoder, а затем фрагментируются.The cookie data is encrypted using IDataProtector, encoded with Base64UrlTextEncoder, then chunked. Так как файл cookie фрагментируется, ограничение на размер одного такого файла, заданное в ASP.NET Core 1.x, не применяется.Because the cookie is chunked, the single cookie size limit found in ASP.NET Core 1.x doesn't apply. Данные файла cookie не сжимаются, так как сжатие зашифрованных данных может привести к проблемам с безопасностью, например атакам CRIME и BREACH.The cookie data isn't compressed because compressing encrypted data can lead to security problems such as the CRIME and BREACH attacks. Дополнительные сведения на поставщике TempData, основанном на файлах cookie, см. в разделе CookieTempDataProvider.For more information on the cookie-based TempData provider, see CookieTempDataProvider.

Выбор поставщика TempDataChoose a TempData provider

Выбор поставщика TempData включает в себя несколько аспектов:Choosing a TempData provider involves several considerations, such as:

  1. Приложение уже использует состояние сеанса?Does the app already use session state? Если это так, использование поставщика TempData для состояния сеанса не требует от приложения никаких дополнительных издержек (кроме объема данных).If so, using the session state TempData provider has no additional cost to the app (aside from the size of the data).
  2. Приложение использует TempData лишь ограниченно, для сравнительно небольших объемов данных (до 500 байт)?Does the app use TempData only sparingly for relatively small amounts of data (up to 500 bytes)? Если это так, поставщик TempData на основе файлов cookie незначительно увеличивает издержки для каждого запроса, переносящего TempData.If so, the cookie TempData provider adds a small cost to each request that carries TempData. В противном случае поставщик TempData для состояния сеанса удобно использовать, чтобы устранить круговой обход большого объема данных в каждом запросе до полного использования TempData.If not, the session state TempData provider can be beneficial to avoid round-tripping a large amount of data in each request until the TempData is consumed.
  3. Приложение выполняется на ферме серверов на нескольких серверах?Does the app run in a server farm on multiple servers? Если это так, не требуется дополнительная настройка для использования поставщика TempData для файлов cookie, за исключением защиты данных (см. статьи Защита данных в ASP.NET Core и Key storage providers in ASP.NET Core (Поставщики хранилища ключей в ASP.NET Core)).If so, there's no additional configuration required to use the cookie TempData provider outside of Data Protection (see Защита данных в ASP.NET Core and Key storage providers).

Примечание

Большинство веб-клиентов (например, веб-браузеры) налагают ограничение на максимальный размер каждого файла cookie и (или) общее количество таких файлов.Most web clients (such as web browsers) enforce limits on the maximum size of each cookie, the total number of cookies, or both. При использовании поставщика TempData на основе файлов cookie убедитесь, что приложение не нарушает эти ограничения.When using the cookie TempData provider, verify the app won't exceed these limits. Учитывайте общий объем данных.Consider the total size of the data. Учитывайте увеличение размеров файла cookie в результате шифрования и фрагментирования.Account for increases in cookie size due to encryption and chunking.

Настройка поставщика TempDataConfigure the TempData provider

Поставщик TempData на основе файлов cookie включен по умолчанию.The cookie-based TempData provider is enabled by default.

Чтобы включить поставщик TempData на основе сеанса, используйте метод расширения AddSessionStateTempDataProvider:To enable the session-based TempData provider, use the AddSessionStateTempDataProvider extension method:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
        .AddSessionStateTempDataProvider();

    services.AddSession();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseSession();
    app.UseMvc();
}

Порядок ПО промежуточного слоя важен.The order of middleware is important. В предыдущем примере исключение InvalidOperationException возникает при вызове UseSession после UseMvc.In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc. Дополнительные сведения см. в разделе Порядок расположения ПО промежуточного слоя.For more information, see Middleware Ordering.

Важно!

Если вы ориентируетесь на .NET Framework и используете поставщик TempData на основе сеансов, добавьте в проект пакет Microsoft.AspNetCore.Session.If targeting .NET Framework and using the session-based TempData provider, add the Microsoft.AspNetCore.Session package to the project.

Строки запросаQuery strings

Вы можете передать ограниченный объем данных из одного запроса в другой, добавив их в строку запроса нового запроса.A limited amount of data can be passed from one request to another by adding it to the new request's query string. Это удобно для захвата состояния в сохраняемом виде, что позволяет обмениваться ссылками с внедренным состоянием по электронной почте или через социальные сети.This is useful for capturing state in a persistent manner that allows links with embedded state to be shared through email or social networks. Поскольку строки запроса URL-адреса являются открытыми, никогда не используйте их для конфиденциальных данных.Because URL query strings are public, never use query strings for sensitive data.

Вдобавок к случайному раскрытию информации включение данных в строки запроса может открыть возможности для атак с подделкой межсайтовых запросов (CSRF), которые могут обманом вынудить пользователей посещать вредоносные веб-сайты во время проверки подлинности.In addition to unintended sharing, including data in query strings can create opportunities for Cross-Site Request Forgery (CSRF) attacks, which can trick users into visiting malicious sites while authenticated. Это позволит злоумышленникам похитить данные пользователей из приложения или предпринимать вредоносные действия от их имени.Attackers can then steal user data from the app or take malicious actions on behalf of the user. Любое сохраненное состояние приложения или сеанса необходимо защитить от атак CSRF.Any preserved app or session state must protect against CSRF attacks. Дополнительные сведения см. в статье Предотвращение атак с подделкой межсайтовых запросов (XSRF/CSRF).For more information, see Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks.

Скрытые поляHidden fields

Данные можно сохранить в скрытых полях формы и опубликовать обратно при следующем запросе.Data can be saved in hidden form fields and posted back on the next request. Это типичное поведение для многостраничных форм.This is common in multi-page forms. Так как клиент может незаконно изменить данные, приложение всегда должно перепроверять данные в скрытых полях.Because the client can potentially tamper with the data, the app must always revalidate the data stored in hidden fields.

HttpContext.ItemsHttpContext.Items

Коллекция HttpContext.Items используется для хранения данных при обработке одного запроса.The HttpContext.Items collection is used to store data while processing a single request. Ее содержимое удаляется после обработки каждого запроса.The collection's contents are discarded after a request is processed. Коллекцию Items часто используют для обеспечения взаимодействия компонентов или ПО промежуточного слоя, когда они выполняются в разные моменты времени во время обработки запроса и не могут передавать параметры напрямую.The Items collection is often used to allow components or middleware to communicate when they operate at different points in time during a request and have no direct way to pass parameters.

В следующем примере ПО промежуточного слоя добавляет isVerified в коллекцию Items.In the following example, middleware adds isVerified to the Items collection.

app.Use(async (context, next) =>
{
    // perform some verification
    context.Items["isVerified"] = true;
    await next.Invoke();
});

Далее в конвейере другое ПО промежуточного слоя может получить доступ к значению isVerified:Later in the pipeline, another middleware can access the value of isVerified:

app.Run(async (context) =>
{
    await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
});

Для ПО промежуточного слоя, которое используется всего одним приложением, допустимы ключи string.For middleware that's only used by a single app, string keys are acceptable. ПО промежуточного слоя, используемое несколькими экземплярами приложения, должно использовать уникальные ключи объекта во избежание конфликтов.Middleware shared between app instances should use unique object keys to avoid key collisions. В следующем примере показано, как использовать уникальный ключ объекта, определенный в классе ПО промежуточного слоя:The following example shows how to use a unique object key defined in a middleware class:

public class HttpContextItemsMiddleware
{
    private readonly RequestDelegate _next;
    public static readonly object HttpContextItemsMiddlewareKey = new Object();

    public HttpContextItemsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Items[HttpContextItemsMiddlewareKey] = "K-9";

        await _next(httpContext);
    }
}

public static class HttpContextItemsMiddlewareExtensions
{
    public static IApplicationBuilder 
        UseHttpContextItemsMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<HttpContextItemsMiddleware>();
    }
}

Другой код может обратиться к значению, хранящемуся в HttpContext.Items, с помощью ключа, предоставляемого классом ПО промежуточного слоя:Other code can access the value stored in HttpContext.Items using the key exposed by the middleware class:

HttpContext.Items
    .TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey, 
        out var middlewareSetValue);
SessionInfo_MiddlewareValue = 
    middlewareSetValue?.ToString() ?? "Middleware value not set!";

Данный подход также позволяет не использовать строки ключей в коде.This approach also has the advantage of eliminating the use of key strings in the code.

КэшCache

Кэширование — это эффективный способ хранения и извлечения данных.Caching is an efficient way to store and retrieve data. Приложение может управлять временем существования элементов кэша.The app can control the lifetime of cached items.

Кэшированные данные не связаны с конкретным запросом, пользователем или сеансом.Cached data isn't associated with a specific request, user, or session. Будьте внимательны и не кэшируйте данные пользователя, которые можно извлечь по запросу другого пользователя.Be careful not to cache user-specific data that may be retrieved by other users' requests.

Дополнительные сведения можно найти по адресу: Кэширование ответов в ASP.NET Core.For more information, see Кэширование ответов в ASP.NET Core.

Внедрение зависимостейDependency Injection

Используйте внедрение зависимостей, чтобы сделать данные доступными для всех пользователей:Use Dependency Injection to make data available to all users:

  1. Определите службу, содержащую данные.Define a service containing the data. Например, определяется класс с именем MyAppData:For example, a class named MyAppData is defined:

    public class MyAppData
    {
        // Declare properties and methods
    }
    
  2. Добавьте класс службы в Startup.ConfigureServices:Add the service class to Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<MyAppData>();
    }
    
  3. Используйте класс службы данных:Consume the data service class:

    public class IndexModel : PageModel
    {
        public IndexModel(MyAppData myService)
        {
            // Do something with the service
            //    Examples: Read data, store in a field or property
        }
    }
    

Распространенные ошибкиCommon errors

  • "Unable to resolve service for type "Microsoft.Extensions.Caching.Distributed.IDistributedCache" while attempting to activate "Microsoft.AspNetCore.Session.DistributedSessionStore"" (Не удается разрешить службу для типа "Microsoft.Extensions.Caching.Distributed.IDistributedCache" при попытке активировать "Microsoft.AspNetCore.Session.DistributedSessionStore")."Unable to resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' while attempting to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore'."

    Обычно она вызвана невозможностью настройки по меньшей мере одной реализации IDistributedCache.This is usually caused by failing to configure at least one IDistributedCache implementation. Дополнительные сведения см. в разделах Распределенное кэширование в ASP.NET Core и Кэширование в памяти в ASP.NET Core.For more information, see Распределенное кэширование в ASP.NET Core and Кэширование в памяти в ASP.NET Core.

  • Если ПО промежуточного слоя для сеанса не удается сохранить сеанс (например, резервное хранилище недоступно), оно регистрирует исключение и запрос выполняется обычным образом.In the event that the session middleware fails to persist a session (for example, if the backing store isn't available), the middleware logs the exception and the request continues normally. Это приводит к непредсказуемому поведению.This leads to unpredictable behavior.

    Например, пользователь сохраняет корзину для покупок в сеансе.For example, a user stores a shopping cart in session. Он добавляет товар в корзину, но фиксация завершается сбоем.The user adds an item to the cart but the commit fails. Приложению неизвестно о сбое, поэтому оно сообщает пользователю, что товар добавлен в корзину, хотя это не так.The app doesn't know about the failure so it reports to the user that the item was added to their cart, which isn't true.

    Для проверки на наличие таких ошибок рекомендуется вызывать await feature.Session.CommitAsync(); из кода приложения по окончании записи в сеанс.The recommended approach to check for errors is to call await feature.Session.CommitAsync(); from app code when the app is done writing to the session. CommitAsync создает исключение, если резервное хранилище недоступно.CommitAsync throws an exception if the backing store is unavailable. Если CommitAsync завершается ошибкой, приложение может обработать исключение.If CommitAsync fails, the app can process the exception. Исключение LoadAsync возникает в таких же условиях, когда хранилище данных недоступно.LoadAsync throws under the same conditions where the data store is unavailable.

Дополнительные ресурсыAdditional resources

Размещение ASP.NET Core в веб-ферме