Estado de sesión y aplicación en ASP.NET CoreSession and app state in ASP.NET Core

Por Rick Anderson, Steve Smith, Diana LaRose y Luke LathamBy Rick Anderson, Steve Smith, Diana LaRose, and Luke Latham

HTTP es un protocolo sin estado.HTTP is a stateless protocol. Sin realizar pasos adicionales, las solicitudes HTTP son mensajes independientes que no conservan los valores de usuario ni el estado de la aplicación.Without taking additional steps, HTTP requests are independent messages that don't retain user values or app state. En este artículo se describen varios enfoques para conservar el estado de la aplicación y los datos de usuario entre las solicitudes.This article describes several approaches to preserve user data and app state between requests.

Vea o descargue el código de ejemplo (cómo descargarlo)View or download sample code (how to download)

Administración de estadoState management

El estado se puede almacenar mediante varios enfoques.State can be stored using several approaches. Cada enfoque se describe más adelante en este tema.Each approach is described later in this topic.

Enfoque de almacenamientoStorage approach Mecanismo de almacenamientoStorage mechanism
CookiesCookies Cookies HTTP (pueden incluir los datos almacenados mediante el código de aplicación del lado servidor)HTTP cookies (may include data stored using server-side app code)
Estado de sesiónSession state Cookies HTTP y código de aplicación del lado servidorHTTP cookies and server-side app code
TempDataTempData Cookies HTTP o estado de sesiónHTTP cookies or session state
Cadenas de consultaQuery strings Cadenas de consulta HTTPHTTP query strings
Campos ocultosHidden fields Campos de formularios HTTPHTTP form fields
HttpContext.ItemsHttpContext.Items Código de aplicación del lado servidorServer-side app code
CachéCache Código de aplicación del lado servidorServer-side app code
Inserción de dependenciasDependency Injection Código de aplicación del lado servidorServer-side app code

CookiesCookies

Las cookies almacenan datos de todas las solicitudes.Cookies store data across requests. Dado que las cookies se envían con cada solicitud, su tamaño debe reducirse al mínimo.Because cookies are sent with every request, their size should be kept to a minimum. Lo ideal es que en cada cookie se almacene un solo identificador con los datos almacenados por la aplicación.Ideally, only an identifier should be stored in a cookie with the data stored by the app. La mayoría de los exploradores restringen el tamaño de las cookies a 4096 bytes.Most browsers restrict cookie size to 4096 bytes. Solo hay disponible un número limitado de cookies para cada dominio.Only a limited number of cookies are available for each domain.

Como las cookies están expuestas a alteraciones, deben validarse por la aplicación.Because cookies are subject to tampering, they must be validated by the app. Los usuarios pueden eliminar las cookies y estas pueden caducar en los clientes.Cookies can be deleted by users and expire on clients. Pero las cookies generalmente son la forma más duradera de persistencia de datos en el cliente.However, cookies are generally the most durable form of data persistence on the client.

Las cookies suelen utilizarse para personalizar el contenido ofrecido a un usuario conocido.Cookies are often used for personalization, where content is customized for a known user. En la mayoría de los casos, el usuario solo se identifica y no se autentica.The user is only identified and not authenticated in most cases. La cookie puede almacenar el nombre de usuario, el nombre de cuenta o el id. de usuario único (por ejemplo, un GUID).The cookie can store the user's name, account name, or unique user ID (such as a GUID). Después, puede usar la cookie para tener acceso a la configuración personalizada del usuario, como su color de fondo del sitio web preferido.You can then use the cookie to access the user's personalized settings, such as their preferred website background color.

Preste atención al reglamento general de protección de datos (GDPR) de la Unión Europea cuando emita cookies y trate con casos de privacidad.Be mindful of the European Union General Data Protection Regulations (GDPR) when issuing cookies and dealing with privacy concerns. Para obtener más información, vea Compatibilidad con el Reglamento general de protección de datos (RGPD) en ASP.NET Core.For more information, see General Data Protection Regulation (GDPR) support in ASP.NET Core.

Estado de sesiónSession state

El estado de sesión es un escenario de ASP.NET Core para el almacenamiento de datos de usuario mientras el usuario examina una aplicación web.Session state is an ASP.NET Core scenario for storage of user data while the user browses a web app. El estado de sesión usa un almacén mantenido por la aplicación para conservar los datos en las solicitudes de un cliente.Session state uses a store maintained by the app to persist data across requests from a client. Los datos de sesión están respaldados por una memoria caché y se consideran datos efímeros y el sitio debería continuar funcionando correctamente sin los datos de sesión.The session data is backed by a cache and considered ephemeral data—the site should continue to function without the session data. Los datos críticos de aplicaciones deben almacenarse en la base de datos de usuario y almacenarse en caché en la sesión solo para optimizar el rendimiento.Critical application data should be stored in the user database and cached in session only as a performance optimization.

Nota

La sesión no es compatible con aplicaciones SignalR porque un concentrador SignalR podría ejecutarse independientemente de un contexto HTTP.Session isn't supported in SignalR apps because a SignalR Hub may execute independent of an HTTP context. Por ejemplo, esto puede ocurrir cuando un concentrador mantiene abierta una solicitud de sondeo larga más allá de la duración del contexto HTTP de la solicitud.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.

Para mantener el estado de sesión, ASP.NET Core proporciona una cookie al cliente que contiene un identificador de sesión, que se envía a la aplicación con cada solicitud.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. La aplicación usa el identificador de sesión para capturar los datos de sesión.The app uses the session ID to fetch the session data.

El estado de sesión muestra los siguientes comportamientos:Session state exhibits the following behaviors:

  • Dado que la cookie de sesión es específica del explorador, las sesiones no se comparten entre los exploradores.Because the session cookie is specific to the browser, sessions aren't shared across browsers.
  • Las cookies de sesión se eliminan cuando finaliza la sesión del explorador.Session cookies are deleted when the browser session ends.
  • Si se recibe una cookie de una sesión que ha expirado, se crea una nueva sesión que usa la misma cookie de sesión.If a cookie is received for an expired session, a new session is created that uses the same session cookie.
  • Las sesiones vacías no se mantienen y la sesión debe tener, al menos un conjunto de valores en ella para que se conserve entre solicitudes.Empty sessions aren't retained—the session must have at least one value set into it to persist the session across requests. Cuando una sesión no se conserva, se genera un nuevo identificador de sesión para cada nueva solicitud.When a session isn't retained, a new session ID is generated for each new request.
  • La aplicación conserva una sesión durante un tiempo limitado después de la última solicitud.The app retains a session for a limited time after the last request. La aplicación especifica un tiempo de espera de sesión o usa el valor predeterminado de 20 minutos.The app either sets the session timeout or uses the default value of 20 minutes. El estado de sesión es ideal para almacenar datos de usuario que son específicos de una sesión determinada, pero que no necesitan conservarse de forma permanente entre las sesiones.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.
  • Los datos de sesión se eliminan cuando se llama a la implementación ISession.Clear o cuando expira la sesión.Session data is deleted either when the ISession.Clear implementation is called or when the session expires.
  • No hay ningún mecanismo predeterminado para informar al código de aplicación que se ha cerrado un explorador del cliente o cuando la cookie de sesión se elimina o caduca en el cliente.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.
  • Las plantillas de Razor Pages y ASP.NET Core MVC guardan conformidad con el Reglamento general de protección de datos (RGPD).The ASP.NET Core MVC and Razor pages templates include support for General Data Protection Regulation (GDPR). Las cookies de estado de sesión no se marcan como esenciales de forma predeterminada, por lo que el estado de sesión no será funcional a menos que el visitante del sitio permita el seguimiento.Session state cookies aren't marked essential by default, so session state isn't functional unless tracking is permitted by the site visitor. Para más información, consulte Compatibilidad de Reglamento general de protección de datos (RGPD) en ASP.NET Core.For more information, see Compatibilidad de Reglamento general de protección de datos (RGPD) en ASP.NET Core.

Advertencia

No almacene datos confidenciales en un estado de sesión.Don't store sensitive data in session state. El usuario podría no cerrar el explorador y borrar la cookie de sesión.The user might not close the browser and clear the session cookie. Algunos exploradores mantienen las cookies de sesión válidas en las ventanas del explorador.Some browsers maintain valid session cookies across browser windows. Es posible que una sesión no esté restringida a un único usuario y que el siguiente usuario continúe examinando la aplicación con la misma cookie de sesión.A session might not be restricted to a single user—the next user might continue to browse the app with the same session cookie.

El proveedor de caché en memoria almacena datos de sesión en la memoria del servidor donde reside la aplicación.The in-memory cache provider stores session data in the memory of the server where the app resides. En un escenario de granja de servidores:In a server farm scenario:

Configurar el estado de sesiónConfigure session state

El paquete Microsoft.AspNetCore.Session, que se incluye en el metapaquete Microsoft.AspNetCore.App, proporciona middleware para administrar el estado de sesión.The Microsoft.AspNetCore.Session package, which is included in the Microsoft.AspNetCore.App metapackage, provides middleware for managing session state. Para habilitar el middleware de sesión, Startup debe contener:To enable the session middleware, Startup must contain:

El código siguiente muestra cómo configurar el proveedor de sesión en memoria con una implementación en memoria de 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();
    }
}

El orden del middleware es importante.The order of middleware is important. En el ejemplo anterior, se produce una excepción InvalidOperationException cuando UseSession se invoca después de UseMvc.In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc. Para obtener más información vea Ordenación de Middleware.For more information, see Middleware Ordering.

HttpContext.Session está disponible después de configurar el estado de sesión.HttpContext.Session is available after session state is configured.

No se puede acceder a HttpContext.Session antes de llamar a UseSession.HttpContext.Session can't be accessed before UseSession has been called.

No se puede crear una nueva sesión con una cookie de sesión nueva después de que la aplicación haya empezado a escribir en la secuencia de respuesta.A new session with a new session cookie can't be created after the app has begun writing to the response stream. La excepción se registra en el registro del servidor web y no se muestra en el explorador.The exception is recorded in the web server log and not displayed in the browser.

Cargar de forma asincrónica el estado de sesiónLoad session state asynchronously

El proveedor de sesión predeterminado de ASP.NET Core carga asincrónicamente los registros de sesión desde la memoria auxiliar subyacente IDistributedCache solo si se llama explícitamente al método ISession.LoadAsync antes que a los métodos TryGetValue, Set o 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. Si primero no se llama a LoadAsync, el registro de sesión subyacente se carga de forma sincrónica, lo que podría conllevar una disminución del rendimiento al escalar.If LoadAsync isn't called first, the underlying session record is loaded synchronously, which can incur a performance penalty at scale.

Para que las aplicaciones impongan este patrón, ajuste las implementaciones de DistributedSessionStore y DistributedSession con versiones que produzcan una excepción si el método LoadAsync no se llama antes que TryGetValue, Set o 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. Registre las versiones ajustadas en el contenedor de servicios.Register the wrapped versions in the services container.

Opciones de sesiónSession options

Para reemplazar los valores predeterminados de la sesión, use SessionOptions.To override session defaults, use SessionOptions.

OpciónOption DESCRIPCIÓNDescription
CookieCookie Determina la configuración usada para crear la cookie.Determines the settings used to create the cookie. Name tiene como valor predeterminado SessionDefaults.CookieName (.AspNetCore.Session).Name defaults to SessionDefaults.CookieName (.AspNetCore.Session). Path tiene como valor predeterminado SessionDefaults.CookiePath (/).Path defaults to SessionDefaults.CookiePath (/). SameSite tiene como valor predeterminado SameSiteMode.Lax (1).SameSite defaults to SameSiteMode.Lax (1). HttpOnly tiene como valor predeterminado true.HttpOnly defaults to true. IsEssential tiene como valor predeterminado false.IsEssential defaults to false.
IdleTimeoutIdleTimeout IdleTimeout indica cuánto tiempo puede estar inactiva la sesión antes de que se abandone su contenido.The IdleTimeout indicates how long the session can be idle before its contents are abandoned. Cada acceso a la sesión restablece el tiempo de espera.Each session access resets the timeout. Este valor solo es aplicable al contenido de la sesión, no a la cookie.This setting only applies to the content of the session, not the cookie. El valor predeterminado es de 20 minutos.The default is 20 minutes.
IOTimeoutIOTimeout El período máximo de tiempo permitido para cargar una sesión del almacén o devolverla a él.The maximum amount of time allowed to load a session from the store or to commit it back to the store. Este valor solo es aplicable a las operaciones asincrónicas.This setting may only apply to asynchronous operations. Puede deshabilitar este tiempo de espera mediante InfiniteTimeSpan.This timeout can be disabled using InfiniteTimeSpan. El valor predeterminado es 1 minuto.The default is 1 minute.

La sesión utiliza una cookie para realizar el seguimiento de las solicitudes emitidas por un solo explorador e identificarlas.Session uses a cookie to track and identify requests from a single browser. De manera predeterminada, esta cookie se denomina .AspNetCore.Session y usa una ruta de acceso de /.By default, this cookie is named .AspNetCore.Session, and it uses a path of /. Dado que el valor predeterminado de la cookie no especifica un dominio, no estará disponible para el script de cliente en la página (porque HttpOnly tiene como valor predeterminado 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).

Para reemplazar los valores predeterminados de la sesión de cookies, use 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;
    });
}

La aplicación usa la propiedad IdleTimeout para determinar el tiempo que una sesión puede estar inactiva antes de que se abandone el contenido de la caché de servidor.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. Esta propiedad es independiente de la expiración de la cookie.This property is independent of the cookie expiration. Cada solicitud que se pasa a través del middleware de sesión restablece el tiempo de espera.Each request that passes through the Session Middleware resets the timeout.

El estado de sesión es no realiza bloqueo.Session state is non-locking. Si dos solicitudes intentan modificar el contenido de una sesión simultáneamente, la última solicitud reemplaza a la primera.If two requests simultaneously attempt to modify the contents of a session, the last request overrides the first. Session se implementa como una sesión coherente, lo que significa que todo el contenido se almacena junto.Session is implemented as a coherent session, which means that all the contents are stored together. Cuando dos solicitudes buscan modificar diferentes valores de sesión, la última solicitud podría reemplazar los cambios de sesión realizados por la primera.When two requests seek to modify different session values, the last request may override session changes made by the first.

Establecer y obtener valores de SessionSet and get Session values

Se accede al estado de sesión desde una clase PageModel de Razor Pages o una clase Controller de MVC con HttpContext.Session.Session state is accessed from a Razor Pages PageModel class or MVC Controller class with HttpContext.Session. Esta propiedad es una implementación de ISession.This property is an ISession implementation.

La implementación ISession proporciona varios métodos de extensión para establecer y recuperar valores de cadena y enteros.The ISession implementation provides several extension methods to set and retrieve integer and string values. Los métodos de extensión están en el espacio de nombres Microsoft.AspNetCore.Http (agregue una instrucción using Microsoft.AspNetCore.Http; para obtener acceso a los métodos de extensión) cuando el proyecto hace referencia al paquete 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. Ambos paquetes están incluidos en el metapaquete Microsoft.AspNetCore.App.Both packages are included in the Microsoft.AspNetCore.App metapackage.

Métodos de extensión ISession:ISession extension methods:

En el ejemplo siguiente se recupera el valor de sesión para la clave IndexModel.SessionKeyName (_Name en la aplicación de ejemplo) en una página de 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)

En el ejemplo siguiente se muestra cómo establecer y obtener un entero y una cadena: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);

Todos los datos de sesión se deben serializar para habilitar un escenario de caché distribuida, incluso cuando se usa la caché en memoria.All session data must be serialized to enable a distributed cache scenario, even when using the in-memory cache. Se proporcionan una cadena mínima y serializadores de número (vea los métodos y los métodos de extensión de ISession).Minimal string and number serializers are provided (see the methods and extension methods of ISession). El usuario debe serializar los tipos complejos mediante otro mecanismo, como JSON.Complex types must be serialized by the user using another mechanism, such as JSON.

Agregue los siguientes métodos de extensión, para establecer y obtener objetos serializables: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);
    }
}

En el ejemplo siguiente se muestra cómo establecer y obtener un objeto serializable con los método de extensión: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 expone TempData de Razor Pages o TempData del controlador.ASP.NET Core exposes the Razor Pages TempData or Controller TempData. Esta propiedad almacena datos hasta que se leen en otra solicitud.This property stores data until it's read in another request. Los métodos Keep(String) y Peek(string) se pueden usar para examinar los datos sin eliminarlos al final de la solicitud.Keep(String) and Peek(string) methods can be used to examine the data without deletion at the end of the request. Keep() marca todos los elementos del diccionario para su retención.Keep() marks all items in the dictionary for retention. TempData es particularmente útil para el redireccionamiento cuando se necesitan los datos para más de una única solicitud.TempData is particularly useful for redirection when data is required for more than a single request. Los proveedores de TempData implementan TempData mediante cookies o estado de sesión.TempData is implemented by TempData providers using either cookies or session state.

Ejemplos de TempDataTempData samples

Considere la siguiente página que crea un cliente:Consider the following page that creates a customer:

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");
    }
}

La siguiente página muestra TempData["Message"]:The following page displays TempData["Message"]:

@page
@model IndexModel

<h1>Peek Contacts</h1>

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

@*Content removed for brevity.*@

En el marcado anterior, al final de la solicitud, TempData["Message"] no se elimina porque se usa Peek.In the preceding markup, at the end of the request, TempData["Message"] is not deleted because Peek is used. Al actualizar la página, aparece TempData["Message"].Refreshing the page displays TempData["Message"].

El marcado siguiente es similar al código anterior, pero usa Keep para conservar los datos al final de la solicitud:The following markup is similar to the preceding code, but uses Keep to preserve the data at the end of the request:

@page
@model IndexModel

<h1>Contacts Keep</h1>

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

@*Content removed for brevity.*@

La navegación entre las páginas IndexPeek y IndexKeep no eliminará TempData["Message"].Navigating between the IndexPeek and IndexKeep pages won't delete TempData["Message"].

El código siguiente muestra TempData["Message"], pero al final de la solicitud, se elimina TempData["Message"]:The following code displays TempData["Message"], but at the end of the request, TempData["Message"] is deleted:

@page
@model IndexModel

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

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

@*Content removed for brevity.*@

Proveedores de TempDataTempData providers

El proveedor TempData basado en cookies se usa de forma predeterminada para almacenar TempData en cookies.The cookie-based TempData provider is used by default to store TempData in cookies.

Los datos de cookie se cifran mediante IDataProtector, codificado con Base64UrlTextEncoder, y después se fragmentan.The cookie data is encrypted using IDataProtector, encoded with Base64UrlTextEncoder, then chunked. Como la cookie está fragmentada, no se aplica el límite de tamaño único de cookie que se encuentra en 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. Los datos de cookie no se comprimen porque la compresión de datos cifrados puede provocar problemas de seguridad como los ataques CRIME y BREACH.The cookie data isn't compressed because compressing encrypted data can lead to security problems such as the CRIME and BREACH attacks. Para obtener más información sobre el proveedor TempData basado en cookies, consulte CookieTempDataProvider.For more information on the cookie-based TempData provider, see CookieTempDataProvider.

Elegir un proveedor TempDataChoose a TempData provider

Elegir un proveedor TempData implica una serie de consideraciones:Choosing a TempData provider involves several considerations, such as:

  1. ¿La aplicación ya usa el estado de sesión?Does the app already use session state? Si es así, el uso del proveedor TempData de estado de sesión no tiene costo adicional para la aplicación (excepto en el tamaño de los datos).If so, using the session state TempData provider has no additional cost to the app (aside from the size of the data).
  2. ¿La aplicación usa TempData con moderación, solo para cantidades relativamente pequeñas de datos (hasta 500 bytes)?Does the app use TempData only sparingly for relatively small amounts of data (up to 500 bytes)? Si es así, el proveedor TempData de cookies agrega un pequeño costo a cada solicitud que transporta TempData.If so, the cookie TempData provider adds a small cost to each request that carries TempData. De lo contrario, el proveedor TempData de estado de sesión puede ser beneficioso para evitar que una gran cantidad de datos hagan un recorrido de ida y vuelta en cada solicitud hasta que se consuma 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. ¿La aplicación se ejecuta en una granja de servidores en varios servidores?Does the app run in a server farm on multiple servers? Si es así, no es necesaria ninguna configuración adicional para usar el proveedor de TempData de cookies además de la protección de datos (vea Protección de datos de ASP.NET Core y Proveedores de almacenamiento de claves).If so, there's no additional configuration required to use the cookie TempData provider outside of Data Protection (see Protección de datos de ASP.NET Core and Key storage providers).

Nota

La mayoría de los clientes de web (por ejemplo, los exploradores web) aplican límites en el tamaño máximo de cada cookie, el número total de cookies o ambos.Most web clients (such as web browsers) enforce limits on the maximum size of each cookie, the total number of cookies, or both. Cuando use el proveedor TempData de cookies, compruebe que la aplicación no supera esos límites.When using the cookie TempData provider, verify the app won't exceed these limits. Tenga en cuenta el tamaño total de los datos.Consider the total size of the data. Cuenta para los aumentos de tamaño de cookie debidos a la fragmentación y el cifrado.Account for increases in cookie size due to encryption and chunking.

Configurar el proveedor TempDataConfigure the TempData provider

El proveedor TempData basado en cookies está habilitado de forma predeterminada.The cookie-based TempData provider is enabled by default.

Para habilitar el proveedor TempData basado en sesión, use el método de extensión 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();
}

El orden del middleware es importante.The order of middleware is important. En el ejemplo anterior, se produce una excepción InvalidOperationException cuando UseSession se invoca después de UseMvc.In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc. Para obtener más información vea Ordenación de Middleware.For more information, see Middleware Ordering.

Importante

Si el destino es .NET Framework y usa el proveedor TempData basado en sesión, agregue el paquete Microsoft.AspNetCore.Session al proyecto.If targeting .NET Framework and using the session-based TempData provider, add the Microsoft.AspNetCore.Session package to the project.

Cadenas de consultaQuery strings

Se puede pasar una cantidad limitada de datos de una solicitud a otra si agrega los datos a la cadena de consulta de la solicitud nueva.A limited amount of data can be passed from one request to another by adding it to the new request's query string. Esto es útil para capturar el estado de una forma persistente que permita que los vínculos con estado insertado se compartan a través del correo electrónico o las redes sociales.This is useful for capturing state in a persistent manner that allows links with embedded state to be shared through email or social networks. Dado que las cadenas de consulta de direcciones URL son públicas, nunca use las cadenas de consulta para datos confidenciales.Because URL query strings are public, never use query strings for sensitive data.

Además del uso compartido no intencionado, la inclusión de datos en las cadenas de consulta puede propiciar ataques de falsificación de solicitud entre sitios (CSRF), cuya intención es engañar a los usuarios para que visiten sitios malintencionados mientras están autenticados.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. Después, los atacantes pueden robar los datos de usuario de la aplicación o realizar acciones malintencionadas en nombre del usuario.Attackers can then steal user data from the app or take malicious actions on behalf of the user. Cualquier estado de sesión o aplicación conservado debe protegerse contra los ataques CSRF.Any preserved app or session state must protect against CSRF attacks. Para más información, vea Preventing Cross-Site Request Forgery (XSRF/CSRF) Attacks (Evitar los ataques de falsificación de solicitud entre sitios [XSRF/CSRF]).For more information, see Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks.

Campos ocultosHidden fields

Los datos pueden guardarse en campos ocultos de formulario e incluirse de nuevo en la siguiente solicitud.Data can be saved in hidden form fields and posted back on the next request. Esto es habitual en los formularios de varias páginas.This is common in multi-page forms. Dado que el cliente puede llegar a alterar los datos, la aplicación siempre debe revalidar los datos almacenados en campos ocultos.Because the client can potentially tamper with the data, the app must always revalidate the data stored in hidden fields.

HttpContext.ItemsHttpContext.Items

La colección HttpContext.Items se usa para almacenar los datos al procesar una única solicitud.The HttpContext.Items collection is used to store data while processing a single request. El contenido de la colección se descarta después de procesar una solicitud.The collection's contents are discarded after a request is processed. A menudo se usa la colección Items para permitir que los componentes o el middleware se comuniquen cuando operan en distintos puntos en el tiempo durante una solicitud y no pueden pasarse parámetros de forma directa.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.

En el ejemplo siguiente, Middleware agrega isVerified a la colección 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();
});

Más adelante en la canalización, otro middleware puede acceder al valor de 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"]}");
});

Si el middleware solo se usa en una única aplicación, se aceptan claves string.For middleware that's only used by a single app, string keys are acceptable. El middleware compartido entre instancias de aplicación debería usar claves de objeto únicas para evitar conflictos de clave.Middleware shared between app instances should use unique object keys to avoid key collisions. En el ejemplo siguiente se muestra cómo usar una clave de objeto única definida en una clase de middleware: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>();
    }
}

Otro código puede tener acceso al valor almacenado en HttpContext.Items con la clave que expone la clase de middleware: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!";

Este enfoque también tiene la ventaja de eliminar el uso de cadenas de claves en el código.This approach also has the advantage of eliminating the use of key strings in the code.

instancias y clavesCache

El almacenamiento en caché es una manera eficaz de almacenar y recuperar datos.Caching is an efficient way to store and retrieve data. La aplicación puede controlar la duración de los elementos almacenados en caché.The app can control the lifetime of cached items.

Los datos almacenados en caché no están asociados a una solicitud, usuario o sesión específicos.Cached data isn't associated with a specific request, user, or session. Procure no almacenar en caché datos específicos de usuario que podrían recuperar las solicitudes de otros usuarios.Be careful not to cache user-specific data that may be retrieved by other users' requests.

Para más información, consulte Almacenamiento en caché de respuestas en ASP.NET Core.For more information, see Almacenamiento en caché de respuestas en ASP.NET Core.

Inserción de dependenciasDependency Injection

Use inserción de dependencias para que los datos estén disponibles para todos los usuarios:Use Dependency Injection to make data available to all users:

  1. Definir un servicio que contiene los datos.Define a service containing the data. Por ejemplo, una clase denominada MyAppData se define:For example, a class named MyAppData is defined:

    public class MyAppData
    {
        // Declare properties and methods
    }
    
  2. Agregue la clase de servicio a Startup.ConfigureServices:Add the service class to Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<MyAppData>();
    }
    
  3. Use la clase de servicio de datos: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
        }
    }
    

Errores comunesCommon errors

  • "No se puede resolver el servicio para el tipo 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' al intentar activar 'Microsoft.AspNetCore.Session.DistributedSessionStore'"."Unable to resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' while attempting to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore'."

    Esto puede deberse a que no se ha configurado al menos una implementación IDistributedCache.This is usually caused by failing to configure at least one IDistributedCache implementation. Para obtener más información, vea Almacenamiento en caché distribuido en ASP.NET Core y Almacenar en memoria caché en ASP.NET Core.For more information, see Almacenamiento en caché distribuido en ASP.NET Core and Almacenar en memoria caché en ASP.NET Core.

  • En caso de que el middleware de sesión no logre conservar una sesión (por ejemplo, si la memoria auxiliar no está disponible), el middleware registra la excepción y la solicitud continúa con normalidad.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. Esto provoca un comportamiento imprevisible.This leads to unpredictable behavior.

    Por ejemplo, un usuario almacena un carro de la compra en la sesión.For example, a user stores a shopping cart in session. El usuario agrega un elemento al carro, pero se produce un error en la confirmación.The user adds an item to the cart but the commit fails. La aplicación no se percata del error y notifica al usuario que el elemento se ha agregado al carro, lo cual no es cierto.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.

    El enfoque recomendado para comprobar los errores es llamar a await feature.Session.CommitAsync(); desde el código de la aplicación cuando esta haya terminado de escribir en la sesión.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 produce una excepción si la memoria auxiliar no está disponible.CommitAsync throws an exception if the backing store is unavailable. Si CommitAsync produce un error, la aplicación puede procesar la excepción.If CommitAsync fails, the app can process the exception. LoadAsync se produce en las mismas condiciones donde el almacén de datos no está disponible.LoadAsync throws under the same conditions where the data store is unavailable.

SignalR y estado de sesiónSignalR and session state

Las aplicaciones de SignalR no deben usar el estado de sesión para almacenar información.SignalR apps should not use session state to store information. Las aplicaciones de SignalR pueden almacenar por estado de conexión en Context.Items en el concentrador.SignalR apps can store per connection state in Context.Items in the hub.

Recursos adicionalesAdditional resources

Hospedaje de ASP.NET Core en una granja de servidores web