Administración del estado y la sesión en ASP.NET Core
Por Rick Anderson, Steve Smith y Diana LaRose
HTTP es un protocolo sin estado. De forma predeterminada, las solicitudes HTTP son mensajes independientes que no conservan los valores de usuario. En este artículo se describen varios enfoques para conservar los datos de usuario entre las solicitudes.
Vea o descargue el código de ejemplo (cómo descargarlo)
Administración de estado
El estado se puede almacenar mediante varios enfoques. Cada enfoque se describe más adelante en este tema.
| Enfoque de almacenamiento | Mecanismo de almacenamiento |
|---|---|
| Cookies | cookies HTTP. Pueden incluir los datos almacenados mediante el código de aplicación del lado servidor. |
| Estado de sesión | cookies HTTP y código de aplicación del lado servidor |
| TempData | cookies HTTP o estado de sesión |
| Cadenas de consulta | Cadenas de consulta HTTP |
| Campos ocultos | Campos de formularios HTTP |
| HttpContext.Items | Código de aplicación del lado servidor |
| Caché | Código de aplicación del lado servidor |
Cookies
Las Cookies almacenan datos de todas las solicitudes. Dado que las cookies se envían con cada solicitud, su tamaño debe reducirse al mínimo. Lo ideal es que en cada cookie se almacene un solo identificador con los datos almacenados por la aplicación. La mayoría de los exploradores restringen el tamaño de las cookies a 4096 bytes. Solo hay disponible un número limitado de cookies para cada dominio.
Como las cookies están expuestas a alteraciones, deben validarse por la aplicación. Los usuarios pueden eliminar las Cookies y estas pueden caducar en los clientes. Pero las cookies generalmente son la forma más duradera de persistencia de datos en el cliente.
Las Cookies suelen utilizarse para personalizar el contenido ofrecido a un usuario conocido. En la mayoría de los casos, el usuario solo se identifica y no se autentica. La cookie puede almacenar el nombre de usuario, el nombre de cuenta o el identificador único del usuario, por ejemplo, un GUID. Se puede usar la cookie para tener acceso a la configuración personalizada del usuario, como su color de fondo preferido del sitio web.
Consulte el Reglamento general de protección de datos (RGPD) de la Unión Europea al emitir cookies y tratar con casos relativos a la privacidad. Para obtener más información, vea Compatibilidad con el Reglamento general de protección de datos (RGPD) en ASP.NET Core.
Estado de sesión
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. El estado de sesión usa un almacén mantenido por la aplicación para conservar los datos en las solicitudes de un cliente. Los datos de sesión están respaldados por una memoria caché y se consideran datos efímeros. El sitio debería continuar funcionando correctamente sin los datos de sesión. 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.
La sesión no se admite en aplicaciones SignalR porque un SignalRconcentrador de se podría ejecutar con independencia de un contexto HTTP. 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.
Para mantener el estado de sesión, ASP.NET Core proporciona una cookie al cliente que contiene un identificador de sesión. El identificador de sesión de la cookie:
- Se envía a la aplicación con cada solicitud.
- Lo usa la aplicación para capturar los datos de la sesión.
El estado de sesión muestra los siguientes comportamientos:
- La cookie de sesión es específica de cada explorador. Las sesiones no se comparten entre los exploradores.
- Las cookies de sesión se eliminan cuando finaliza la sesión del explorador.
- 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.
- No se conservan las sesiones vacías. La sesión debe tener al menos un conjunto de valores para que se conserve en todas las solicitudes. Cuando una sesión no se conserva, se genera un nuevo identificador de sesión para cada nueva solicitud.
- La aplicación conserva una sesión durante un tiempo limitado después de la última solicitud. La aplicación especifica un tiempo de espera de sesión o usa el valor predeterminado de 20 minutos. El estado de sesión es ideal para almacenar datos de usuario:
- Que son específicos de una sesión determinada.
- Que no necesitan conservarse de forma permanente en las sesiones.
- Los datos de sesión se eliminan cuando se llama a la implementación ISession.Clear o cuando expira la sesión.
- 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.
- Las cookies de estado de sesión no están marcadas como esenciales de forma predeterminada. De este modo, el estado de sesión no es funcional a menos que el visitante del sitio permita el seguimiento. Para obtener más información, vea Reglamento general de protección de datos (RGPD) en ASP.NET Core.
Advertencia
No almacene datos confidenciales en un estado de sesión. El usuario podría no cerrar el explorador y borrar la cookie de sesión. Algunos exploradores mantienen las cookies de sesión válidas en las ventanas del explorador. Es posible que una sesión no esté restringida a un único usuario. Así pues, el siguiente usuario podría continuar examinando la aplicación con la misma cookie de sesión.
El proveedor de caché en memoria almacena datos de sesión en la memoria del servidor donde reside la aplicación. En un escenario de granja de servidores:
- Use sesiones permanentes para asociar cada sesión a una instancia de aplicación específica en un servidor individual. Azure App Service usa enrutamiento de solicitud de aplicaciones (ARR) para exigir sesiones permanentes de forma predeterminada. Pero las sesiones permanentes pueden afectar a la escalabilidad y complicar la actualización de las aplicaciones web. Un enfoque mejor consiste en usar una memoria caché distribuida de Redis o SQL Server, que no requiere sesiones permanentes. Para obtener más información, vea Almacenamiento en caché distribuido en ASP.NET Core.
- La cookie de sesión se cifra mediante IDataProtector. La protección de datos debe configurarse correctamente para que lea las cookies de sesión en cada equipo. Para más información, vea ASP.NET Core Protección de datos y Proveedores de almacenamiento de claves.
Configurar el estado de sesión
El paquete Microsoft.AspNetCore.Session:
- Está incluido implícitamente en el marco.
- Proporciona middleware para administrar el estado de sesión.
Para habilitar el middleware de sesión, Startup debe contener:
- Cualquiera de las cachés de memoria IDistributedCache. La implementación de
IDistributedCachese usa como una memoria auxiliar para la sesión. Para obtener más información, vea Almacenamiento en caché distribuido en ASP.NET Core. - Una llamada a AddSession en
ConfigureServices. - Una llamada a UseSession en
Configure.
El código siguiente muestra cómo configurar el proveedor de sesión en memoria con una implementación en memoria de IDistributedCache:
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();
});
}
}
El código anterior establece un tiempo de expiración breve para simplificar la prueba.
El orden del middleware es importante. Llame a UseSession después de llamar a UseRouting y antes de la llamada a UseEndpoints. Consulte Orden del middleware.
HttpContext.Session está disponible después de configurar el estado de sesión.
No se puede acceder a HttpContext.Session antes de llamar a UseSession.
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. La excepción se registra en el registro del servidor web y no se muestra en el explorador.
Cargar de forma asincrónica el estado de sesión
El proveedor de sesión predeterminado de ASP.NET Core carga de manera asincrónica registros de sesión del almacén de respaldo IDistributedCache subyacente solo si se llama al método ISession.LoadAsync de forma explícita antes que a los métodos TryGetValue, Set o Remove. 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.
Para que las aplicaciones impongan este patrón, encapsule las implementaciones DistributedSessionStore y DistributedSession con versiones que inicien una excepción si no se llama al método LoadAsync antes que a TryGetValue, Set o Remove. Registre las versiones ajustadas en el contenedor de servicios.
Opciones de sesión
Para reemplazar los valores predeterminados de la sesión, use SessionOptions.
| Opción | Descripción |
|---|---|
| Cookie | Determina la configuración usada para crear la cookie. Name se establece de forma predeterminada en SessionDefaults.CookieName (.AspNetCore.Session). Path se establece de forma predeterminada en SessionDefaults.CookiePath (/). SameSite se establece de forma predeterminada en SameSiteMode.Lax (1). HttpOnly se establece de forma predeterminada en true. IsEssential se establece de forma predeterminada en false. |
| IdleTimeout | IdleTimeout indica cuánto tiempo puede estar inactiva la sesión antes de que se abandone su contenido. Cada acceso a la sesión restablece el tiempo de espera. Este valor solo es aplicable al contenido de la sesión, no a la cookie. El valor predeterminado es de 20 minutos. |
| IOTimeout | El período máximo de tiempo permitido para cargar una sesión del almacén o devolverla a él. Este valor solo es aplicable a las operaciones asincrónicas. Este tiempo de espera se puede deshabilitar mediante InfiniteTimeSpan. El valor predeterminado es 1 minuto. |
La sesión utiliza una cookie para realizar el seguimiento de las solicitudes emitidas por un solo explorador e identificarlas. De manera predeterminada, esta cookie se denomina .AspNetCore.Session y usa una ruta de acceso de /. 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 se establece de forma predeterminada en true).
Para reemplazar los valores predeterminados de la sesión de cookies, use SessionOptions:
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();
}
La aplicación usa la propiedad IdleTimeout para determinar el tiempo que una sesión puede estar inactiva antes de que se abandone su contenido en la caché del servidor. Esta propiedad es independiente de la expiración de la cookie. Cada solicitud que se pasa a través del middleware de sesión restablece el tiempo de espera.
El estado de sesión es no realiza bloqueo. Si dos solicitudes intentan modificar el contenido de una sesión simultáneamente, la última solicitud reemplaza a la primera. Session se implementa como una sesión coherente, lo que significa que todo el contenido se almacena junto. 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.
Establecer y obtener valores de Session
Se tiene acceso al estado de sesión desde la clase PageModel de Razor Pages o desde la clase Controller de MVC con HttpContext.Session. Esta propiedad es una implementación de ISession.
La implementación ISession proporciona varios métodos de extensión para establecer y recuperar valores de cadena y enteros. Los nuevos métodos de extensión se encuentran en el espacio de nombres Microsoft.AspNetCore.Http.
Métodos de extensión ISession:
- Get(ISession, String)
- GetInt32(ISession, String)
- GetString(ISession, String)
- SetInt32(ISession, String, Int32)
- SetString(ISession, String, String)
En el ejemplo siguiente se recupera el valor de sesión de la clave IndexModel.SessionKeyName (_Name en la aplicación de ejemplo) de una página de Razor Pages:
@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:
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. Los métodos de extensión de ISession proporcionan serializadores de cadenas y enteros. El usuario debe serializar los tipos complejos mediante otro mecanismo, como JSON.
Use el siguiente código de ejemplo para serializar objetos:
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);
}
}
En el ejemplo siguiente se muestra cómo establecer y obtener un objeto serializable con la clase SessionExtensions:
// Requires SessionExtensions from sample download.
if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
{
HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}
TempData
ASP.NET Core expone TempData de Razor Pages o TempData del controlador. Esta propiedad almacena datos hasta que se leen en otra solicitud. Los métodos Keep(String) y Peek(string) se pueden usar para examinar los datos sin eliminarlos al final de la solicitud. Keep marca todos los elementos del diccionario para su retención. TempData es:
- Útil para el redireccionamiento cuando se necesitan los datos de más de una única solicitud.
- Implementada por los proveedores de
TempDatamediante cookies o el estado de sesión.
Ejemplos de TempData
Considere la siguiente página que crea un cliente:
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"]:
@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. Al actualizar la página, se muestra el contenido de TempData["Message"].
El marcado siguiente es similar al código anterior, pero usa Keep para conservar los datos al final de la solicitud:
@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"].
El código siguiente muestra TempData["Message"], pero al final de la solicitud, se elimina TempData["Message"]:
@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 TempData
El proveedor TempData basado en cookies se usa de forma predeterminada para almacenar TempData en cookies.
Los datos de cookies se cifran mediante IDataProtector, codificados con Base64UrlTextEncoder para posteriormente fragmentarse. El tamaño máximo de la cookie es inferior a 4096 bytes debido al cifrado y a la fragmentación. 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. Para más información sobre el proveedor TempData basado en cookies, consulte CookieTempDataProvider.
Elegir un proveedor TempData
Elegir un proveedor TempData implica una serie de consideraciones:
- ¿La aplicación ya usa el estado de sesión? 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).
- ¿La aplicación usa TempData con moderación, solo para cantidades relativamente pequeñas de datos (hasta 500 bytes)? Si es así, el proveedor TempData de cookies agrega un pequeño costo a cada solicitud que transporta 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.
- ¿La aplicación se ejecuta en una granja de servidores en varios servidores? 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 ASP.NET Core Protección de datos y Proveedores de almacenamiento de claves).
La mayoría de los clientes 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. Cuando use el proveedor TempData de cookies, asegúrese de que la aplicación no supera esos límites. Tenga en cuenta el tamaño total de los datos. Cuenta para los aumentos de tamaño de cookie debidos a la fragmentación y el cifrado.
Configurar el proveedor TempData
El proveedor TempData basado en cookies está habilitado de forma predeterminada.
Para habilitar el proveedor TempData basado en sesión, use el método de extensión AddSessionStateTempDataProvider. Solo se requiere una llamada a AddSessionStateTempDataProvider:
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();
});
}
Cadenas de consulta
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. 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. Dado que las cadenas de consulta de direcciones URL son públicas, nunca use las cadenas de consulta para datos confidenciales.
Además del uso compartido no intencionado, la inclusión de datos en cadenas de consulta puede exponer la aplicación a ataques de falsificación de solicitud entre sitios (CSRF). Cualquier estado de sesión conservado debe protegerse contra los ataques CSRF. Para obtener más información, vea Evitar ataques de falsificación de solicitud entre sitios (XSRF/CSRF) en ASP.NET Core.
Campos ocultos
Los datos pueden guardarse en campos ocultos de formulario e incluirse de nuevo en la siguiente solicitud. Esto es habitual en los formularios de varias páginas. Dado que el cliente puede llegar a alterar los datos, la aplicación siempre debe revalidar los datos almacenados en campos ocultos.
HttpContext.Items
La colección HttpContext.Items se usa para almacenar los datos al procesar una única solicitud. El contenido de la colección se descarta después de procesar una solicitud. 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.
En el ejemplo siguiente, el middleware agrega isVerified a la colección Items:
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"]}");
});
});
}
Si el middleware solo se usa en una única aplicación, se aceptan claves string fijas. El middleware compartido entre aplicaciones debería usar claves de objeto únicas para evitar conflictos de clave. En el ejemplo siguiente se muestra cómo usar una clave de objeto única definida en una clase de middleware:
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>();
}
}
Otro código puede tener acceso al valor almacenado en HttpContext.Items con la clave que expone la clase de middleware:
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.
instancias y claves
El almacenamiento en caché es una manera eficaz de almacenar y recuperar datos. La aplicación puede controlar la duración de los elementos almacenados en caché. Para obtener más información, vea Almacenamiento en caché de respuestas en ASP.NET Core.
Los datos almacenados en caché no están asociados a una solicitud, usuario o sesión específicos. Procure no almacenar en caché datos específicos de usuario que se puedan recuperar mediante las solicitudes de otros usuarios.
Para almacenar en caché datos de toda la aplicación, consulte Caché en memoria en ASP.NET Core.
Errores comunes
"No se puede resolver el servicio para el tipo 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' al intentar activar 'Microsoft.AspNetCore.Session.DistributedSessionStore'".
Normalmente, esto se debe a que no se ha configurado al menos una implementación
IDistributedCache. Para obtener más información, vea Almacenamiento en caché distribuido en ASP.NET Core y Caché en memoria en ASP.NET Core.
Si el middleware de sesión no puede conservar una sesión:
- El middleware registra la excepción y la solicitud se procesa con normalidad.
- Esto provoca un comportamiento imprevisible.
El middleware de sesión puede no conservar una sesión si la memoria auxiliar no está disponible. Por ejemplo, un usuario almacena un carro de la compra en la sesión. El usuario agrega un elemento al carro, pero se produce un error en la confirmación. 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.
El enfoque recomendado para comprobar si hay errores es llamar a await feature.Session.CommitAsync cuando la aplicación haya terminado de escribir en la sesión. CommitAsync produce una excepción si la memoria auxiliar no está disponible. Si CommitAsync produce un error, la aplicación puede procesar la excepción. LoadAsync se produce en las mismas condiciones cuando el almacén de datos no está disponible.
SignalR y estado de la sesión
Las aplicaciones SignalR no deben usar el estado de sesión para almacenar información. Las aplicaciones SignalR pueden almacenarse por estado de conexión en Context.Items en el concentrador.
Recursos adicionales
Por Rick Anderson, Steve Smith, Diana LaRose y Luke Latham
HTTP es un protocolo sin estado. Sin realizar pasos adicionales, las solicitudes HTTP son mensajes independientes que no conservan los valores de usuario ni el estado de la aplicación. En este artículo se describen varios enfoques para conservar el estado de la aplicación y los datos de usuario entre las solicitudes.
Vea o descargue el código de ejemplo (cómo descargarlo)
Administración de estado
El estado se puede almacenar mediante varios enfoques. Cada enfoque se describe más adelante en este tema.
| Enfoque de almacenamiento | Mecanismo de almacenamiento |
|---|---|
| Cookies | cookies HTTP (pueden incluir los datos almacenados mediante el código de aplicación del lado servidor) |
| Estado de sesión | cookies HTTP y código de aplicación del lado servidor |
| TempData | cookies HTTP o estado de sesión |
| Cadenas de consulta | Cadenas de consulta HTTP |
| Campos ocultos | Campos de formularios HTTP |
| HttpContext.Items | Código de aplicación del lado servidor |
| Caché | Código de aplicación del lado servidor |
| Inserción de dependencias | Código de aplicación del lado servidor |
Cookies
Las Cookies almacenan datos de todas las solicitudes. Dado que las cookies se envían con cada solicitud, su tamaño debe reducirse al mínimo. Lo ideal es que en cada cookie se almacene un solo identificador con los datos almacenados por la aplicación. La mayoría de los exploradores restringen el tamaño de las cookies a 4096 bytes. Solo hay disponible un número limitado de cookies para cada dominio.
Como las cookies están expuestas a alteraciones, deben validarse por la aplicación. Los usuarios pueden eliminar las Cookies y estas pueden caducar en los clientes. Pero las cookies generalmente son la forma más duradera de persistencia de datos en el cliente.
Las Cookies suelen utilizarse para personalizar el contenido ofrecido a un usuario conocido. En la mayoría de los casos, el usuario solo se identifica y no se autentica. La cookie puede almacenar el nombre de usuario, el nombre de cuenta o el identificador único del usuario (por ejemplo, un 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.
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. Para obtener más información, vea Compatibilidad con el Reglamento general de protección de datos (RGPD) en ASP.NET Core.
Estado de sesión
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. El estado de sesión usa un almacén mantenido por la aplicación para conservar los datos en las solicitudes de un cliente. 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. 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.
Nota
La sesión no se admite en aplicaciones SignalR porque un SignalRconcentrador de se podría ejecutar con independencia de un contexto HTTP. 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.
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. La aplicación usa el identificador de sesión para capturar los datos de sesión.
El estado de sesión muestra los siguientes comportamientos:
- Dado que la cookie de sesión es específica del explorador, las sesiones no se comparten entre los exploradores.
- Las cookies de sesión se eliminan cuando finaliza la sesión del explorador.
- 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.
- 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. Cuando una sesión no se conserva, se genera un nuevo identificador de sesión para cada nueva solicitud.
- La aplicación conserva una sesión durante un tiempo limitado después de la última solicitud. La aplicación especifica un tiempo de espera de sesión o usa el valor predeterminado de 20 minutos. 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.
- Los datos de sesión se eliminan cuando se llama a la implementación ISession.Clear o cuando expira la sesión.
- 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.
- Las plantillas de Razor Pages y ASP.NET Core MVC guardan conformidad con el Reglamento general de protección de datos (RGPD). 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. Para obtener más información, vea Reglamento general de protección de datos (RGPD) en ASP.NET Core.
Advertencia
No almacene datos confidenciales en un estado de sesión. El usuario podría no cerrar el explorador y borrar la cookie de sesión. Algunos exploradores mantienen las cookies de sesión válidas en las ventanas del explorador. Es posible que una sesión no esté restringida a un único usuario—el siguiente usuario continúa examinando la aplicación con la misma cookie de sesión.
El proveedor de caché en memoria almacena datos de sesión en la memoria del servidor donde reside la aplicación. En un escenario de granja de servidores:
- Use sesiones permanentes para asociar cada sesión a una instancia de aplicación específica en un servidor individual. Azure App Service usa enrutamiento de solicitud de aplicaciones (ARR) para exigir sesiones permanentes de forma predeterminada. Pero las sesiones permanentes pueden afectar a la escalabilidad y complicar la actualización de las aplicaciones web. Un enfoque mejor consiste en usar una memoria caché distribuida de Redis o SQL Server, que no requiere sesiones permanentes. Para obtener más información, vea Almacenamiento en caché distribuido en ASP.NET Core.
- La cookie de sesión se cifra mediante IDataProtector. La protección de datos debe configurarse correctamente para que lea las cookies de sesión en cada equipo. Para más información, vea ASP.NET Core Protección de datos y Proveedores de almacenamiento de claves.
Configurar el estado de sesión
El paquete Microsoft.AspNetCore.Session, que se incluye en el metapaquete Microsoft.AspNetCore.App, proporciona middleware para administrar el estado de sesión. Para habilitar el middleware de sesión, Startup debe contener:
- Cualquiera de las cachés de memoria IDistributedCache. La implementación de
IDistributedCachese usa como una memoria auxiliar para la sesión. Para obtener más información, vea Almacenamiento en caché distribuido en ASP.NET Core. - Una llamada a AddSession en
ConfigureServices. - Una llamada a UseSession en
Configure.
El código siguiente muestra cómo configurar el proveedor de sesión en memoria con una implementación en memoria de 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. En el ejemplo anterior, se produce una excepción InvalidOperationException cuando UseSession se invoca después de UseMvc. Para obtener más información vea Ordenación de Middleware.
HttpContext.Session está disponible después de configurar el estado de sesión.
No se puede acceder a HttpContext.Session antes de llamar a UseSession.
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. La excepción se registra en el registro del servidor web y no se muestra en el explorador.
Cargar de forma asincrónica el estado de sesión
El proveedor de sesión predeterminado de ASP.NET Core carga de manera asincrónica registros de sesión del almacén de respaldo IDistributedCache subyacente solo si se llama al método ISession.LoadAsync de forma explícita antes que a los métodos TryGetValue, Set o Remove. 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.
Para que las aplicaciones impongan este patrón, encapsule las implementaciones DistributedSessionStore y DistributedSession con versiones que inicien una excepción si no se llama al método LoadAsync antes que a TryGetValue, Set o Remove. Registre las versiones ajustadas en el contenedor de servicios.
Opciones de sesión
Para reemplazar los valores predeterminados de la sesión, use SessionOptions.
| Opción | Descripción |
|---|---|
| Cookie | Determina la configuración usada para crear la cookie. Name se establece de forma predeterminada en SessionDefaults.CookieName (.AspNetCore.Session). Path se establece de forma predeterminada en SessionDefaults.CookiePath (/). SameSite se establece de forma predeterminada en SameSiteMode.Lax (1). HttpOnly se establece de forma predeterminada en true. IsEssential se establece de forma predeterminada en false. |
| IdleTimeout | IdleTimeout indica cuánto tiempo puede estar inactiva la sesión antes de que se abandone su contenido. Cada acceso a la sesión restablece el tiempo de espera. Este valor solo es aplicable al contenido de la sesión, no a la cookie. El valor predeterminado es de 20 minutos. |
| IOTimeout | El período máximo de tiempo permitido para cargar una sesión del almacén o devolverla a él. Este valor solo es aplicable a las operaciones asincrónicas. Este tiempo de espera se puede deshabilitar mediante InfiniteTimeSpan. El valor predeterminado es 1 minuto. |
La sesión utiliza una cookie para realizar el seguimiento de las solicitudes emitidas por un solo explorador e identificarlas. De manera predeterminada, esta cookie se denomina .AspNetCore.Session y usa una ruta de acceso de /. 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 se establece de forma predeterminada en true).
Para reemplazar los valores predeterminados de la sesión de cookies, 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 su contenido en la caché del servidor. Esta propiedad es independiente de la expiración de la cookie. Cada solicitud que se pasa a través del middleware de sesión restablece el tiempo de espera.
El estado de sesión es no realiza bloqueo. Si dos solicitudes intentan modificar el contenido de una sesión simultáneamente, la última solicitud reemplaza a la primera. Session se implementa como una sesión coherente, lo que significa que todo el contenido se almacena junto. 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.
Establecer y obtener valores de Session
Se tiene acceso al estado de sesión desde la clase PageModel de Razor Pages o desde la clase Controller de MVC con HttpContext.Session. Esta propiedad es una implementación de ISession.
La implementación ISession proporciona varios métodos de extensión para establecer y recuperar valores de cadena y enteros. 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. Ambos paquetes están incluidos en el metapaquete Microsoft.AspNetCore.App.
Métodos de extensión ISession:
- Get(ISession, String)
- GetInt32(ISession, String)
- GetString(ISession, String)
- SetInt32(ISession, String, Int32)
- SetString(ISession, String, String)
En el ejemplo siguiente se recupera el valor de sesión de la clave IndexModel.SessionKeyName (_Name en la aplicación de ejemplo) de una página de Razor Pages:
@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:
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. Los métodos de extensión de ISession proporcionan serializadores de cadenas y enteros. El usuario debe serializar los tipos complejos mediante otro mecanismo, como JSON.
Agregue los siguientes métodos de extensión, para establecer y obtener objetos serializables:
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:
// 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);
}
TempData
ASP.NET Core expone TempData de Razor Pages o TempData del controlador. Esta propiedad almacena datos hasta que se leen en otra solicitud. Los métodos Keep(String) y Peek(string) se pueden usar para examinar los datos sin eliminarlos al final de la solicitud. Keep() marca todos los elementos del diccionario para su retención. TempData es particularmente útil para el redireccionamiento cuando se necesitan los datos para más de una única solicitud. Los proveedores de TempData implementan TempData mediante cookies o estado de sesión.
Ejemplos de TempData
Considere la siguiente página que crea un cliente:
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"]:
@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. Al actualizar la página, aparece TempData["Message"].
El marcado siguiente es similar al código anterior, pero usa Keep para conservar los datos al final de la solicitud:
@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"].
El código siguiente muestra TempData["Message"], pero al final de la solicitud, se elimina TempData["Message"]:
@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 TempData
El proveedor TempData basado en cookies se usa de forma predeterminada para almacenar TempData en cookies.
Los datos de cookies se cifran mediante IDataProtector, codificados con Base64UrlTextEncoder para posteriormente fragmentarse. 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. 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. Para más información sobre el proveedor TempData basado en cookies, consulte CookieTempDataProvider.
Elegir un proveedor TempData
Elegir un proveedor TempData implica una serie de consideraciones:
- ¿La aplicación ya usa el estado de sesión? 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).
- ¿La aplicación usa TempData con moderación, solo para cantidades relativamente pequeñas de datos (hasta 500 bytes)? Si es así, el proveedor TempData de cookies agrega un pequeño costo a cada solicitud que transporta 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.
- ¿La aplicación se ejecuta en una granja de servidores en varios servidores? 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 ASP.NET Core Protección de datos y Proveedores de almacenamiento de claves).
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. Cuando use el proveedor TempData de cookies, asegúrese de que la aplicación no supera esos límites. Tenga en cuenta el tamaño total de los datos. Cuenta para los aumentos de tamaño de cookie debidos a la fragmentación y el cifrado.
Configurar el proveedor TempData
El proveedor TempData basado en cookies está habilitado de forma predeterminada.
Para habilitar el proveedor TempData basado en sesión, use el método de extensión AddSessionStateTempDataProvider:
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. En el ejemplo anterior, se produce una excepción InvalidOperationException cuando UseSession se invoca después de UseMvc. Para obtener más información vea Ordenación de Middleware.
Importante
Si el destino es .NET Framework y usa el proveedor TempData basado en sesión, agregue el paquete Microsoft.AspNetCore.Session al proyecto.
Cadenas de consulta
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. 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. Dado que las cadenas de consulta de direcciones URL son públicas, nunca use las cadenas de consulta para datos confidenciales.
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. Después, los atacantes pueden robar los datos de usuario de la aplicación o realizar acciones malintencionadas en nombre del usuario. Cualquier estado de sesión o aplicación conservado debe protegerse contra los ataques CSRF. Para obtener más información, vea Evitar ataques de falsificación de solicitud entre sitios (XSRF/CSRF) en ASP.NET Core.
Campos ocultos
Los datos pueden guardarse en campos ocultos de formulario e incluirse de nuevo en la siguiente solicitud. Esto es habitual en los formularios de varias páginas. Dado que el cliente puede llegar a alterar los datos, la aplicación siempre debe revalidar los datos almacenados en campos ocultos.
HttpContext.Items
La colección HttpContext.Items se usa para almacenar los datos al procesar una única solicitud. El contenido de la colección se descarta después de procesar una solicitud. 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.
En el ejemplo siguiente, Middleware agrega isVerified a la colección Items.
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:
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. El middleware compartido entre instancias de aplicación debería usar claves de objeto únicas para evitar conflictos de clave. En el ejemplo siguiente se muestra cómo usar una clave de objeto única definida en una clase de middleware:
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:
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.
instancias y claves
El almacenamiento en caché es una manera eficaz de almacenar y recuperar datos. La aplicación puede controlar la duración de los elementos almacenados en caché.
Los datos almacenados en caché no están asociados a una solicitud, usuario o sesión específicos. Procure no almacenar en caché datos específicos de usuario que podrían recuperar las solicitudes de otros usuarios.
Para obtener más información, vea Almacenamiento en caché de respuestas en ASP.NET Core.
Inserción de dependencias
Use inserción de dependencias para que los datos estén disponibles para todos los usuarios:
Definir un servicio que contiene los datos. Por ejemplo, una clase denominada
MyAppDatase define:public class MyAppData { // Declare properties and methods }Agregue la clase de servicio a
Startup.ConfigureServices:public void ConfigureServices(IServiceCollection services) { services.AddSingleton<MyAppData>(); }Use la clase de servicio de datos:
public class IndexModel : PageModel { public IndexModel(MyAppData myService) { // Do something with the service // Examples: Read data, store in a field or property } }
Errores comunes
"No se puede resolver el servicio para el tipo 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' al intentar activar 'Microsoft.AspNetCore.Session.DistributedSessionStore'".
Esto puede deberse a que no se ha configurado al menos una implementación
IDistributedCache. Para obtener más información, vea Almacenamiento en caché distribuido en ASP.NET Core y Caché en memoria 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. Esto provoca un comportamiento imprevisible.
Por ejemplo, un usuario almacena un carro de la compra en la sesión. El usuario agrega un elemento al carro, pero se produce un error en la confirmación. 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.
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.CommitAsyncproduce una excepción si la memoria auxiliar no está disponible. SiCommitAsyncproduce un error, la aplicación puede procesar la excepción.LoadAsyncse produce en las mismas condiciones donde el almacén de datos no está disponible.
SignalR y estado de la sesión
Las aplicaciones SignalR no deben usar el estado de sesión para almacenar información. Las aplicaciones SignalR pueden almacenarse por estado de conexión en Context.Items en el concentrador.