ASP. Session and state management in. Net core (Microsoft documentation)

Posted by brooky on Mon, 10 Jan 2022 07:14:23 +0100

State management

There are several ways to store state. Each method is described later in this topic.

State management
Storage methodStorage mechanism
Cookie HTTP cookie. This may include data stored using server-side application code.
Session State HTTP cookie s and server-side application code
TempData HTTP cookie or session state
Query Strings HTTP query string
Hidden Fields HTTP form fields
HttpContext.Items Server side application code
Cache Server side application code

Cookies

Cookies store data between requests. Because cookies are sent with each request, their size should be kept to a minimum. Ideally, only the identifier should be stored in the cookie, while the data is stored by the application. Most browser cookies are limited to 4096 bytes. Only a limited number of cookies are available per domain.

Since cookies are easily tampered with, they must be verified by the server. Cookies on the client may be deleted or expired by the user. However, cookies are usually the most persistent form of data persistence on the client.

Cookies are often used for personalization, where the content is customized for known users. In most cases, only users are identified, but they are not authenticated. Cookies can store user names, account names, or unique user ID s (such as guids). Cookies can be used to access the user's personalization settings, such as the preferred website background color.

When publishing cookie s and dealing with privacy issues, see EU general data protection regulation (GDPR) . For more information, see ASP. General data protection regulations (GDPR) support in. Net core.

Session state

Session state is an ASP used to store user data when users browse Web applications Net core solution. The session state uses the storage maintained by the application to save all the data requested by the client. Session data is supported by the cache and is treated as temporary data. The site should continue to run without session data. Critical application data should be stored in the user database and cached only as performance optimization sessions.

SignalR The app does not support sessions because SignalR Center May execute independently of the HTTP context. For example, this can happen when a long polling request opened by the hub exceeds the lifetime of the requested HTTP context.

ASP.NET Core maintains the session state by providing a cookie containing the session ID to the client. Cookie session ID:

  • Will be sent to the app with each request.
  • Used by the application to extract session data.

Session state has the following behavior:

  • Session cookie s are browser specific. Sessions are not shared across browsers.
  • Delete the session cookie at the end of the browser session.
  • If an expired session cookie is received, a new session using the same session cookie is created.
  • Empty sessions are not reserved. At least one value must be set in the session to save all requested sessions. When the session is not reserved, a new session ID is generated for each new request.
  • The app has limited time to keep the session since the last request. Apply to set the session timeout, or use the default value of 20 minutes. Session state is suitable for storing user data in the following cases:
    • Specific to a particular session.
    • Data does not need to be stored permanently across sessions.
  • Session data is calling ISession.Clear Implementation or delete when session expires.
  • There is no default mechanism to inform the application code that the client browser has been closed or the session cookie on the client has been deleted or expired.
  • By default, session state cookie s are not marked as basic. Session state does not work unless site visitors allow tracking. For more information, see ASP. General data protection regulations (GDPR) support in. Net core.

Warning

Do not store sensitive data in session state. Users may not close the browser or clear session cookies. Some browsers retain valid session cookies between browser windows. Sessions may not be limited to a single user. The next user may continue to use the same session cookie to browse the application.

The in memory cache provider stores session data in the memory of the server where the application resides. In the server farm scenario:

Configure session state

Microsoft.AspNetCore.Session Package:

  • Implicitly contained by the frame.
  • Provides middleware for managing session state.

To enable session middleware, Startup {must include:

The following code demonstrates how to use the default in memory implementation of {IDistributedCache} to set the in memory session provider:

C # replication
 
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

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

        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
            options.Cookie.IsEssential = true;
        });

        services.AddControllersWithViews();
        services.AddRazorPages();
    }

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

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseSession();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapRazorPages();
        });
    }
}

The previous code sets a short timeout to simplify testing.

The order of middleware is very important. Call UseSession after UseRouting and UseEndpoints. see also Middleware sorting.

After configuring the session state, HttpContext.Session Available.

Httpcontext cannot be accessed before calling {UseSession} Session.

After the application has started writing to the response stream, a new session with a new session cookie cannot be created. This exception is logged in the Web server log but not displayed in the browser.

Load session state asynchronously

Only when ISession.LoadAsync The method is to precede TryGetValue,Set Or Remove When the method is explicitly called, ASP The default session provider in the. Net core will start from the base IDistributedCache Load session records asynchronously in backing store. If {LoadAsync is not called first, the underlying session records are loaded synchronously, which may have a large impact on performance.

To have the app enforce this pattern, wrap it with a version that throws an exception when the {LoadAsync} method does not call before {TryGetValue, Set} or {Remove} DistributedSessionStore And DistributedSession Implementation. The wrapped version registered in the service container.

Session options

To override session defaults, use SessionOptions.

Session options
optiondescribe
Cookie Determines the settings used to create cookie s.   Name Default to SessionDefaults.CookieName (.AspNetCore.Session).  Path Default to SessionDefaults.CookiePath (/).  SameSite Default to SameSiteMode.Lax (1).  HttpOnly The default is true.   IsEssential The default is false.
IdleTimeout IdleTimeout displays how long content can be idle before abandoning its content. The timeout is reset for each session access. This setting applies only to session content, not cookie s. The default is 20 minutes.
IOTimeout The maximum length of time allowed to load a session from the store or commit it back to the store. This setting may only apply to asynchronous operations. Can use InfiniteTimeSpan To disable this timeout. The default value is 1 minute.

The session uses cookies to track and identify requests from a single browser. By default, this cookie is named AspNetCore.Session and use the path /. Because the cookie default does not specify a domain, it cannot be used by client scripts on the page (because HttpOnly Default = true).

To override cookie session defaults, use SessionOptions:

C # replication
 
public void ConfigureServices(IServiceCollection services)
{
    services.AddDistributedMemoryCache();

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

    services.AddControllersWithViews();
    services.AddRazorPages();
}

Application use IdleTimeout Property to determine how long after the session is idle, its contents in the server cache will be discarded. This property is independent of the cookie expiration time. adopt Session Middleware Each request passed resets the timeout.

The session state is unlocked. If two requests try to modify the content of the same session at the same time, the latter request replaces the previous request. Session} is implemented as a continuous session, which means that all content is stored together. When two requests attempt to modify different session values, the latter request may override the session changes made by the previous one.

Setting and getting session values

Session status is through Razor Pages PageModel Class or contains HttpContext.Session MVC for Controller Class. This property is ISession Implementation.

The ISession # implementation provides several extended methods for setting and retrieving integer and string values. Extension method at Microsoft.AspNetCore.Http Namespace.

ISession} extension method:

The following example retrieves the index model in the Razor Pages page The session value of the sessionkeyname key (_namein the example application):

C # replication
 
@page
@using Microsoft.AspNetCore.Http
@model IndexModel

...

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

The following example shows how to set and get integers and Strings:

C # replication
 
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 the distributed caching scheme, even when in memory caching is used. String and integer serializers are ISession The extension method is provided. Users must serialize complex types using another mechanism, such as JSON.

Serialize the object using the following sample code:

C # replication
 
public static class SessionExtensions
{
    public static void Set<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonSerializer.Serialize(value));
    }

    public static T Get<T>(this ISession session, string key)
    {
        var value = session.GetString(key);
        return value == null ? default : JsonSerializer.Deserialize<T>(value);
    }
}

The following example demonstrates how to use the SessionExtensions class to set and get serializable objects:

C # replication
 
// Requires SessionExtensions from sample download.
if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
{
    HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}

TempData

ASP.NET Core exposes Razor Pages TempData Or controller TempData . This property reads the data before another request reads the data.   Keep(String) And Peek(string) Method can be used to check data without deleting it at the end of the request.   Keep All items in the dictionary are marked for retention. TempData is:

  • Useful for redirection when multiple requests require data.
  • Use cookie s or session state through the TempData provider.

TempData sample

Consider creating the following pages for the customer:

C # replication
 
public class CreateModel : PageModel
{
    private readonly RazorPagesContactsContext _context;

    public CreateModel(RazorPagesContactsContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";

        return RedirectToPage("./IndexPeek");
    }
}

The following page displays: tempdata [message]:

CSHTML copy
 
@page
@model IndexModel

<h1>Peek Contacts</h1>

@{
    if (TempData.Peek("Message") != null)
    {
        <h3>Message: @TempData.Peek("Message")</h3>
    }
}

@*Content removed for brevity.*@

In the previous tag, at the end of the request, @ TempData["Message"] will not be deleted because @ Peek is being used. The refresh page will display the contents of {TempData["Message"].

The following tags are similar to the previous code, but use {Keep} to retain data at the end of the request:

CSHTML copy
 
@page
@model IndexModel

<h1>Contacts Keep</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
    TempData.Keep("Message");
}

@*Content removed for brevity.*@

Navigating between IndexPeek and IndexKeep pages does not delete {TempData["Message"].

The following code shows: TempData["Message"], but will be deleted at the end of the request: TempData["Message"]:

CSHTML copy
 
@page
@model IndexModel

<h1>Index no Keep or Peek</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
}

@*Content removed for brevity.*@

TempData provider

By default, TempData is stored in a cookie using the cookie based TempData provider.

cookie data is used first IDataProtector (use) Base64UrlTextEncoder Encoding) and then block processing. Due to encryption and blocking, the maximum cookie size is less than 4096 bytes . cookie data is not compressed because compressing encrypted data can cause security problems, such as CRIME And BREACH Attack. To learn more about the cookie based TempData provider, see CookieTempDataProvider.

Select TempData provider

Selecting a TempData provider involves several considerations, such as:

  • Is session state used by the app? If so, using the session state TempData provider has no additional cost to the application (except the size of the data).
  • Does the application only use TempData for a relatively small amount of data (up to 500 bytes)? If so, the cookie TempData provider will add less cost to each request carrying TempData. If not, the session state TempData provider helps avoid switching large amounts of data back and forth in each request before using TempData.
  • Does the application run in a server farm on multiple servers? If so, the cookie TempData provider can be used outside of data protection without any other configuration (see) ASP.NET Core data protection and Key store provider).

Most Web clients, such as Web browsers, enforce limits on the maximum size of each cookie and the total number of cookies. When using the cookie TempData provider, verify that the application does not exceed These restrictions . Consider the total size of the data. Explain the increase in cookie size caused by encryption and blocking.

Configure TempData provider

The cookie based TempData provider is enabled by default.

To enable the session based TempData provider, use the AddSessionStateTempDataProvider Extension method. Just call AddSessionStateTempDataProvider:

C # replication
 
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews()
        .AddSessionStateTempDataProvider();
    services.AddRazorPages()
        .AddSessionStateTempDataProvider();

    services.AddSession();
}

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

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseSession();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
    });
}

Query string

Limited data can be passed from one request to another by adding it to the query string of the new request. This facilitates capturing state in a persistent way that allows links to embedded state to be shared via email or social networks. Since URL query strings are public, do not use query strings for sensitive data.

In addition to accidental sharing, including data in the query string can also cause problems for the application Cross Site Request Forgery (CSRF) Attack. Any reserved session state must be protected against CSRF attacks. For more information, see Prevent cross Site Request Forgery (XSRF/CSRF) attacks on ASP NET Core.

Hide field

Data can be saved in hidden form fields and posted back on the next request. This is common in multi page forms. Since the client may tamper with the data, the application must always revalidate the data stored in the hidden field.

HttpContext.Items

HttpContext.Items Collection is used to store data when processing a single request. Discard the contents of the collection after processing the request. Typically, the {Items} collection is used to allow components or middleware to communicate when they operate at different points in time during the request without directly passing parameters.

In the following example, middleware Add "isVerified" to the "Items" collection:

C # replication
 
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    app.UseRouting();

    app.Use(async (context, next) =>
    {
        logger.LogInformation($"Before setting: Verified: {context.Items["isVerified"]}");
        context.Items["isVerified"] = true;
        await next.Invoke();
    });

    app.Use(async (context, next) =>
    {
        logger.LogInformation($"Next: Verified: {context.Items["isVerified"]}");
        await next.Invoke();
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
        });
    });
}

For middleware used only in a single application, fixed string key is acceptable. Middleware shared between applications should use unique object keys to avoid key conflicts. The following example demonstrates how to use the unique object key defined in the middleware class:

C # replication
 
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 app)
    {
        return app.UseMiddleware<HttpContextItemsMiddleware>();
    }
}

Other code can be accessed using the key exposed through the middleware class and stored in httpcontext Values in items:

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

This approach also has the advantage of avoiding using key strings in your code.

cache

Caching is an effective way to store and retrieve data. Applications can control the lifetime of cached items. For more information, see ASP. Response caching in. Net core.

Cached data is not associated with a specific request, user, or session. Do not cache user specific data that may be requested to be retrieved by other users.

To cache application wide data, see ASP. In memory cache in net core.

Common errors

  • "Cannot resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' when trying to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore'."

    This is usually caused by not being able to configure at least one implementation of {IDistributedCache}. For more information, see ASP.NET Core And ASP. In memory cache in net core.

If session middleware cannot keep the session:

  • The middleware records an exception and the request continues normally.
  • This can lead to unpredictable behavior.

If backup storage is not available, session middleware may not be able to retain sessions. For example, a user stores a shopping cart in a session. The user added the item to the shopping cart, but the submission failed. The app is unaware of this failure, so it reports to the user that the item has been added to the shopping cart, but this is not the case.

The recommended way to check such errors is to finish writing the application to the session and call await feature.. Session. CommitAsync. If fallback storage is not available, then CommitAsync An exception was thrown. If , CommitAsync , fails, the application can handle exceptions. Under the same conditions as when the data store is not available, LoadAsync Throw exception

Topics: .NET