Gestão de sessões e estados no ASP.NET Core
Por Rick Anderson, Kirk Larkine Diana LaRose
HTTP é um protocolo sem estado. Por padrão, as solicitações HTTP são mensagens independentes que não retêm valores de usuário. Este artigo descreve várias abordagens para preservar os dados do usuário entre as solicitações.
Para obter orientação sobre gestão de estado Blazor, que adiciona ou substitui as diretrizes deste artigo, consulte ASP.NET Core Blazor gestão de estado.
Gestão do Estado
O estado pode ser armazenado usando várias abordagens. Cada abordagem é descrita mais adiante neste artigo.
Abordagem de armazenamento | Mecanismo de armazenamento |
---|---|
Biscoitos | Cookies HTTP. Pode incluir dados armazenados usando o código do aplicativo do lado do servidor. |
Estado da sessão | Cookies HTTP e código de aplicativo do lado do servidor |
TempData | Cookies HTTP ou estado da sessão |
Cadeias de caracteres de consulta | Cadeias de caracteres de consulta HTTP |
Campos ocultos | Campos de formulário HTTP |
HttpContext.Items | Código do aplicativo do lado do servidor |
Cache | Código do aplicativo do lado do servidor |
Gerenciamento de estado baseado em contexto SignalR/Blazor Server e HTTP
SignalR aplicativos não devem usar o estado da sessão e outras abordagens de gerenciamento de estado que dependem de um contexto HTTP estável para armazenar informações.
SignalR aplicativos podem armazenar o estado por conexão em Context.Items
no hub. Para obter mais informações e abordagens alternativas de gerenciamento de estado para aplicativos Blazor Server, consulte ASP.NET Core Blazor state management.
Biscoitos
Os cookies armazenam dados entre pedidos. Uma vez que os cookies são enviados a cada pedido, o seu tamanho deve ser reduzido ao mínimo. Idealmente, apenas um identificador deve ser armazenado em um cookie com os dados armazenados pela aplicação. A maioria dos navegadores restringe cookie tamanho a 4096 bytes. Apenas um número limitado de cookies está disponível para cada domínio.
Como os cookies estão sujeitos a adulteração, eles devem ser validados pelo aplicativo. Os cookies podem ser eliminados pelos utilizadores e expirar nos clientes. No entanto, os cookies são geralmente a forma mais durável de persistência de dados no cliente.
Os cookies são frequentemente utilizados para personalização, onde o conteúdo é personalizado para um utilizador conhecido. O usuário só é identificado e não autenticado na maioria dos casos. O cookie pode armazenar o nome do usuário, o nome da conta ou o ID de usuário exclusivo, como um GUID. O cookie pode ser usado para acessar as configurações personalizadas do usuário, como a cor de fundo do site preferida.
Consulte os do Regulamento Geral de Proteção de Dados da União Europeia (GDPR) ao emitir cookies e lidar com preocupações de privacidade. Para obter mais informações, consulte o suporte ao Regulamento Geral sobre a Proteção de Dados (RGPD) no ASP.NET Core.
Estado da sessão
O estado da sessão é um cenário ASP.NET Core para armazenamento de dados do usuário enquanto o usuário navega em um aplicativo Web. O estado da sessão usa um repositório mantido pelo aplicativo para persistir dados entre solicitações de um cliente. Os dados da sessão são apoiados por um cache e considerados dados efêmeros. O site deve continuar a funcionar sem os dados da sessão. Os dados críticos do aplicativo devem ser armazenados no banco de dados do usuário e armazenados em cache na sessão apenas como uma otimização de desempenho.
Não há suporte para sessão em aplicativos SignalR porque um Hub SignalR pode ser executado independentemente de um contexto HTTP. Por exemplo, isso pode ocorrer quando uma solicitação de sondagem longa é mantida aberta por um hub além do tempo de vida do contexto HTTP da solicitação.
ASP.NET Core mantém o estado da sessão fornecendo um cookie ao cliente que contém uma ID de sessão. O ID da sessão cookie:
- É enviado para a aplicação com cada pedido.
- É usado pelo aplicativo para buscar os dados da sessão.
O estado da sessão exibe os seguintes comportamentos:
- A sessão cookie é específica para o navegador. As sessões não são compartilhadas entre navegadores.
- Os cookies de sessão são eliminados quando a sessão do navegador termina.
- Se uma cookie for recebida para uma sessão expirada, será criada uma nova sessão que usará a mesma sessão cookie.
- As sessões vazias não são mantidas. A sessão deve ter pelo menos um valor definido para persistir a sessão entre solicitações. Quando uma sessão não é mantida, uma nova ID de sessão é gerada para cada nova solicitação.
- O aplicativo mantém uma sessão por um tempo limitado após a última solicitação. O aplicativo define o tempo limite da sessão ou usa o valor padrão de 20 minutos. O estado da sessão é ideal para armazenar dados do usuário:
- Isso é específico para uma sessão específica.
- Onde os dados não exigem armazenamento permanente entre sessões.
- Os dados da sessão são excluídos quando a implementação do ISession.Clear é chamada ou quando a sessão expira.
- Não há nenhum mecanismo padrão para informar ao código da aplicação que um navegador cliente foi fechado ou quando a sessão cookie foi eliminada ou expirada no cliente.
- Os cookies de estado de sessão não são marcados como essenciais por padrão. O estado da sessão não é funcional, a menos que o rastreamento seja permitido pelo visitante do site. Para obter mais informações, consulte o suporte ao Regulamento Geral sobre a Proteção de Dados (RGPD) no ASP.NET Core.
- Nota: Não há substituição para o recurso de sessão sem cookies do ASP.NET Framework porque ele é considerado inseguro e pode levar a ataques de fixação de sessão.
Advertência
Não armazene dados confidenciais no estado da sessão. O usuário pode não fechar o navegador e limpar a sessão cookie. Alguns navegadores mantêm cookies de sessão válidos nas janelas do navegador. Uma sessão pode não estar restrita a um único usuário. O próximo usuário pode continuar a navegar no aplicativo com a mesma sessão cookie.
O provedor de cache na memória armazena dados de sessão na memória do servidor onde o aplicativo reside. Num cenário de grupo de servidores:
- Utilize sessões persistentes para vincular cada sessão a uma instância de aplicação específica em um servidor individual. Serviço de Aplicativo do Azure usa de Roteamento de Solicitação de Aplicativo (ARR) para impor sessões fixas por padrão. No entanto, sessões adesivas podem afetar a escalabilidade e complicar as atualizações do aplicativo Web. Uma abordagem melhor é usar um cache distribuído Redis ou SQL Server, que não requer sessões adesivas. Para obter mais informações, consulte Cache distribuído no ASP.NET Core.
- A sessão cookie é encriptada através IDataProtector. A Proteção de Dados deve ser configurada corretamente para ler cookies de sessão em cada máquina. Para obter mais informações, consulte Visão geral da Proteção de Dados do ASP.NET Core e Provedores de Armazenamento de Chaves.
Configurar o estado da sessão
O middleware para gerenciar o estado da sessão está incluído na estrutura. Para habilitar o middleware de sessão, Program.cs
deve conter:
- Qualquer um dos IDistributedCache caches de memória. A implementação
IDistributedCache
é usada como armazenamento auxiliar para sessões. Para obter mais informações, consulte Cache distribuído no ASP.NET Core. - Uma chamada para AddSession
- Uma chamada para UseSession
O código a seguir mostra como configurar o provedor de sessão em memória com uma implementação padrão de IDistributedCache
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
app.MapDefaultControllerRoute();
app.Run();
O código anterior define um curto tempo limite para simplificar o teste.
A ordem do middleware é importante. Ligue para UseSession
depois de UseRouting
e antes de MapRazorPages
e MapDefaultControllerRoute
. Consulte Middleware Ordering.
HttpContext.Session está disponível após a configuração do estado da sessão.
HttpContext.Session
não pode ser acessado antes que UseSession
tenha sido chamado.
Uma nova sessão com uma nova ID de sessão cookie não pode ser criada depois do aplicativo ter começado a gravar no fluxo de resposta. A exceção é registrada no log do servidor Web e não é exibida no navegador.
Carregar o estado da sessão de forma assíncrona
O provedor de sessão padrão no ASP.NET Core carrega registros de sessão do armazenamento de backup de IDistributedCache subjacente de forma assíncrona somente se o método ISession.LoadAsync for explicitamente chamado antes dos métodos TryGetValue, Setou Remove. Se LoadAsync
não for chamado primeiro, o registro de sessão subjacente será carregado de forma síncrona, o que pode incorrer em uma penalidade de desempenho em escala.
Para que as aplicações implementem este padrão, envolva as implementações de DistributedSessionStore e DistributedSession com versões que gerem uma exceção se o método LoadAsync
não for chamado antes de TryGetValue
, Set
ou Remove
. Registre as versões encapsuladas no contêiner de serviços.
Opções de sessão
Para substituir os padrões de sessão, use SessionOptions.
Opção | Descrição |
---|---|
Cookie | Determina as configurações usadas para criar o cookie.
Name utiliza como valor padrão SessionDefaults.CookieName (.AspNetCore.Session ).
Path tem como padrão SessionDefaults.CookiePath (/ ).
SameSite assume como padrão SameSiteMode.Lax (1 ).
HttpOnly assume como padrão true .
IsEssential, por predefinição, é false . |
IdleTimeout | O IdleTimeout indica por quanto tempo a sessão pode ficar ociosa antes que seu conteúdo seja abandonado. Cada acesso à sessão redefine o tempo limite. Esta definição aplica-se apenas ao conteúdo da sessão, não ao cookie. O padrão é 20 minutos. |
IOTimeout | A quantidade máxima de tempo permitida para carregar uma sessão da loja ou confirmá-la de volta à loja. Essa configuração pode se aplicar apenas a operações assíncronas. Esse tempo limite pode ser desativado usando InfiniteTimeSpan. O padrão é 1 minuto. |
A sessão usa um cookie para rastrear e identificar solicitações de um único navegador. Por padrão, esse cookie é chamado .AspNetCore.Session
e usa um caminho de /
. Como o padrão cookie não especifica um domínio, ele não é disponibilizado para o script do lado do cliente na página (porque o padrão HttpOnly é definido como true
).
Para alterar os padrões de sessão cookie, utilize SessionOptions.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.Cookie.Name = ".AdventureWorks.Session";
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.IsEssential = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
app.MapDefaultControllerRoute();
app.Run();
O aplicativo usa a propriedade IdleTimeout para determinar por quanto tempo uma sessão pode ficar ociosa antes que seu conteúdo no cache do servidor seja abandonado. Esta propriedade é independente da expiração de cookie. Cada solicitação que passa pelo Middleware de Sessão redefine o tempo limite.
O estado da sessão é sem bloqueio. Se duas solicitações simultaneamente tentarem modificar o conteúdo de uma sessão, a última solicitação substituirá a primeira.
Session
é implementado como uma sessão coerente, o que significa que todos os conteúdos são armazenados em conjunto. Quando duas solicitações procuram modificar valores de sessão diferentes, a última solicitação pode substituir as alterações de sessão feitas pela primeira.
Definir e obter valores de sessão
O estado da sessão é acessado a partir de uma classe Razor Pages PageModel ou classe MVC Controller com HttpContext.Session. Esta propriedade é uma implementação do ISession.
A implementação ISession
fornece vários métodos de extensão para definir e recuperar valores inteiros e de cadeia de caracteres. Os métodos de extensão estão no namespace Microsoft.AspNetCore.Http.
ISession
métodos de extensão:
- Get(ISession, String)
- GetInt32(ISession, String)
- GetString(ISession, String)
- SetInt32(ISession, String, Int32)
- SetString(ISession, String, String)
O exemplo a seguir recupera o valor da sessão para a chave IndexModel.SessionKeyName
(_Name
no aplicativo de exemplo) em uma página Razor Pages:
@page
@using Microsoft.AspNetCore.Http
@model IndexModel
...
Name: @HttpContext.Session.GetString(IndexModel.SessionKeyName)
O exemplo a seguir mostra como definir e obter um inteiro e uma cadeia de caracteres:
public class IndexModel : PageModel
{
public const string SessionKeyName = "_Name";
public const string SessionKeyAge = "_Age";
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
if (string.IsNullOrEmpty(HttpContext.Session.GetString(SessionKeyName)))
{
HttpContext.Session.SetString(SessionKeyName, "The Doctor");
HttpContext.Session.SetInt32(SessionKeyAge, 73);
}
var name = HttpContext.Session.GetString(SessionKeyName);
var age = HttpContext.Session.GetInt32(SessionKeyAge).ToString();
_logger.LogInformation("Session Name: {Name}", name);
_logger.LogInformation("Session Age: {Age}", age);
}
}
A marcação a seguir exibe os valores da sessão em uma Página Razor:
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<div class="text-center">
<p><b>Name:</b> @HttpContext.Session.GetString("_Name");<b>Age:
</b> @HttpContext.Session.GetInt32("_Age").ToString()</p>
</div>
Todos os dados da sessão devem ser serializados para habilitar um cenário de cache distribuído, mesmo ao usar o cache na memória. Os serializadores de cadeia de caracteres e inteiros são fornecidos pelos métodos de extensão de ISession. Tipos complexos devem ser serializados pelo usuário usando outro mecanismo, como JSON.
Use o seguinte código de exemplo 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);
}
}
O exemplo a seguir mostra como definir e obter um objeto serializável com a classe SessionExtensions
:
using Microsoft.AspNetCore.Mvc.RazorPages;
using Web.Extensions; // SessionExtensions
namespace SessionSample.Pages
{
public class Index6Model : PageModel
{
const string SessionKeyTime = "_Time";
public string? SessionInfo_SessionTime { get; private set; }
private readonly ILogger<Index6Model> _logger;
public Index6Model(ILogger<Index6Model> logger)
{
_logger = logger;
}
public void OnGet()
{
var currentTime = DateTime.Now;
// Requires SessionExtensions from sample.
if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
{
HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}
_logger.LogInformation("Current Time: {Time}", currentTime);
_logger.LogInformation("Session Time: {Time}",
HttpContext.Session.Get<DateTime>(SessionKeyTime));
}
}
}
Advertência
O armazenamento de um objeto dinâmico na sessão deve ser usado com cuidado, pois há muitos problemas que podem ocorrer com objetos serializados. Para obter mais informações, consulte sessões devem ter permissão para armazenar objetos (dotnet/aspnetcore #18159).
TempData
ASP.NET Core expõe as Razor Pages TempData ou Controller TempData. Essa propriedade armazena dados até que sejam lidos em outra solicitação. Os métodos Keep(String) e Peek(string) podem ser usados para examinar os dados sem exclusão no final da solicitação.
Manter marca todos os itens no dicionário para manutenção.
TempData
é:
- Útil para redirecionamento quando os dados são necessários para mais de uma única solicitação.
- Implementado por provedores de
TempData
utilizando cookies ou estado de sessão.
Exemplos de TempData
Considere a seguinte página que cria um 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");
}
}
A página a seguir exibe TempData["Message"]
:
@page
@model IndexModel
<h1>Peek Contacts</h1>
@{
if (TempData.Peek("Message") != null)
{
<h3>Message: @TempData.Peek("Message")</h3>
}
}
@*Content removed for brevity.*@
Na marcação anterior, no final da solicitação, TempData["Message"]
não é excluído porque Peek
é usado. Ao atualizar a página, irá exibir o conteúdo do TempData["Message"]
.
A marcação a seguir é semelhante ao código anterior, mas usa Keep
para preservar os dados no final da solicitação:
@page
@model IndexModel
<h1>Contacts Keep</h1>
@{
if (TempData["Message"] != null)
{
<h3>Message: @TempData["Message"]</h3>
}
TempData.Keep("Message");
}
@*Content removed for brevity.*@
Navegar entre as páginas IndexPeek e IndexKeep não excluirá TempData["Message"]
.
O código a seguir exibe TempData["Message"]
, mas no final da solicitação, TempData["Message"]
é excluído:
@page
@model IndexModel
<h1>Index no Keep or Peek</h1>
@{
if (TempData["Message"] != null)
{
<h3>Message: @TempData["Message"]</h3>
}
}
@*Content removed for brevity.*@
Fornecedores TempData
O provedor TempData baseado em cookieé usado por padrão para armazenar TempData em cookies.
Os dados cookie são criptografados usando IDataProtector, codificados com Base64UrlTextEncodere, em seguida, fragmentados. O tamanho máximo cookie é inferior a 4096 bytes devido à criptografia e fragmentação. Os dados cookie não são compactados porque a compactação de dados criptografados pode levar a problemas de segurança, como ataques CRIME e BREACH. Para obter mais informações sobre o provedor TempData baseado em cookie, consulte CookieTempDataProvider.
Escolha um provedor TempData
A escolha de um provedor TempData envolve várias considerações, como:
- O aplicativo já usa o estado da sessão? Nesse caso, usar o provedor TempData de estado de sessão não tem custo adicional para o aplicativo além do tamanho dos dados.
- O aplicativo usa o TempData apenas com moderação para quantidades relativamente pequenas de dados, até 500 bytes? Em caso afirmativo, o provedor cookie TempData adiciona um pequeno custo a cada solicitação que carrega TempData. Caso contrário, o provedor TempData do estado da sessão pode ser benéfico para evitar a ida e volta de uma grande quantidade de dados em cada solicitação até que o TempData seja consumido.
- A aplicação é executada num parque de servidores em vários servidores? Nesse caso, não há nenhuma configuração adicional necessária para usar o provedor cookie TempData fora da Proteção de Dados. Para obter mais informações, consulte ASP.NET Core Visão Geral da Proteção de Dados e Provedores de Armazenamento de Chaves.
A maioria dos clientes da Web, como navegadores da Web, impõe limites ao tamanho máximo de cada cookie e ao número total de cookies. Ao usar o provedor cookie TempData, assegure-se de que o aplicativo não excederá esses limites. Considere o tamanho total dos dados. Considere aumentos no tamanho de cookie devido à criptografia e fragmentação.
Configurar o provedor TempData
O provedor TempData baseado em cookieestá habilitado por padrão.
Para habilitar o provedor TempData baseado em sessão, use o método de extensão AddSessionStateTempDataProvider. Apenas uma chamada para AddSessionStateTempDataProvider
é necessária:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages()
.AddSessionStateTempDataProvider();
builder.Services.AddControllersWithViews()
.AddSessionStateTempDataProvider();
builder.Services.AddSession();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
app.MapDefaultControllerRoute();
app.Run();
Parâmetros de consulta
Uma quantidade limitada de dados pode ser passada de uma solicitação para outra, adicionando-a à cadeia de caracteres de consulta da nova solicitação. Isso é útil para capturar o estado de forma persistente que permite que links com o estado incorporado sejam compartilhados por e-mail ou redes sociais. Como as cadeias de caracteres de consulta de URL são públicas, nunca use cadeias de caracteres de consulta para dados confidenciais.
Além do compartilhamento não intencional, a inclusão de dados em cadeias de caracteres de consulta pode expor o aplicativo a ataques de CSRF (Cross-Site Request Forgery). Qualquer estado de sessão preservado deve proteger contra ataques CSRF. Para obter mais informações, consulte Prevenir ataques de falsificação de solicitação entre sites (XSRF/CSRF) no ASP.NET Core.
Campos ocultos
Os dados podem ser salvos em campos de formulário ocultos e postados novamente na próxima solicitação. Isso é comum em formulários de várias páginas. Como o cliente pode potencialmente adulterar os dados, o aplicativo sempre deve revalidar os dados armazenados em campos ocultos.
HttpContext.Items
A coleção HttpContext.Items é usada para armazenar dados durante o processamento de uma única solicitação. O conteúdo da coleção é descartado após o processamento de uma solicitação. A coleção Items
é frequentemente usada para permitir que componentes ou middleware se comuniquem quando operam em diferentes pontos no tempo durante uma solicitação e não têm uma maneira direta de passar parâmetros.
No exemplo a seguir, middleware adiciona isVerified
à coleção Items
:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
ILogger logger = app.Logger;
app.Use(async (context, next) =>
{
// context.Items["isVerified"] is null
logger.LogInformation($"Before setting: Verified: {context.Items["isVerified"]}");
context.Items["isVerified"] = true;
await next.Invoke();
});
app.Use(async (context, next) =>
{
// context.Items["isVerified"] is true
logger.LogInformation($"Next: Verified: {context.Items["isVerified"]}");
await next.Invoke();
});
app.MapGet("/", async context =>
{
await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
});
app.Run();
Para o middleware que é usado apenas numa única aplicação, é improvável que o uso de uma chave fixa string
cause uma colisão de chave. No entanto, para evitar completamente a possibilidade de uma colisão de chaves, um object
pode ser usado como uma chave de item. Essa abordagem é particularmente útil para middleware compartilhado entre aplicativos e também tem a vantagem de eliminar o uso de cadeias de caracteres de chave no código. O exemplo a seguir mostra como usar uma chave object
definida em uma classe middleware:
public class HttpContextItemsMiddleware
{
private readonly RequestDelegate _next;
public static readonly object HttpContextItemsMiddlewareKey = new();
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>();
}
}
Outro código pode acessar o valor armazenado em HttpContext.Items
usando a chave exposta pela classe middleware:
public class Index2Model : PageModel
{
private readonly ILogger<Index2Model> _logger;
public Index2Model(ILogger<Index2Model> logger)
{
_logger = logger;
}
public void OnGet()
{
HttpContext.Items
.TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey,
out var middlewareSetValue);
_logger.LogInformation("Middleware value {MV}",
middlewareSetValue?.ToString() ?? "Middleware value not set!");
}
}
Cache
O cache é uma maneira eficiente de armazenar e recuperar dados. O aplicativo pode controlar o tempo de vida dos itens armazenados em cache. Para obter mais informações, consulte cache de resposta no ASP.NET Core.
Os dados armazenados em cache não estão associados a uma solicitação, usuário ou sessão específica. Não armazene em cache dados específicos do usuário que possam ser recuperados por outras solicitações do usuário.
Para armazenar em cache dados de todo o aplicativo, consulte Cache na memória no ASP.NET Core.
Verificando o estado da sessão
ISession.IsAvailable destina-se a verificar falhas transitórias. Chamar IsAvailable
antes que o middleware da sessão seja executado gera uma InvalidOperationException
.
As bibliotecas que precisam testar a disponibilidade da sessão podem usar HttpContext.Features.Get<ISessionFeature>()?.Session != null
.
Erros comuns
"Não é possível resolver o serviço para o tipo 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' ao tentar ativar 'Microsoft.AspNetCore.Session.DistributedSessionStore'."
Isso geralmente é causado por não configurar pelo menos uma implementação
IDistributedCache
. Para obter mais informações, consulte Cache distribuído no ASP.NET Core e Cache na memória no ASP.NET Core.
Se o middleware de sessão não conseguir persistir uma sessão:
- O middleware registra a exceção e a solicitação continua normalmente.
- Isso leva a um comportamento imprevisível.
O middleware de sessão pode falhar em manter uma sessão se o armazenamento subjacente não estiver disponível. Por exemplo, um usuário armazena um carrinho de compras na sessão. O usuário adiciona um item ao carrinho, mas a confirmação falha. O aplicativo não sabe sobre a falha, então relata ao usuário que o item foi adicionado ao carrinho, o que não é verdade.
A abordagem recomendada para verificar se há erros é chamar await feature.Session.CommitAsync
quando o aplicativo terminar de gravar na sessão.
CommitAsync lança uma exceção se o armazenamento de suporte não estiver disponível. Se CommitAsync
falhar, o aplicativo poderá processar a exceção.
LoadAsync é lançado nas mesmas condições quando o armazenamento de dados não está disponível.
Recursos adicionais
Por Rick Anderson, Kirk Larkine Diana LaRose
HTTP é um protocolo sem estado. Por padrão, as solicitações HTTP são mensagens independentes que não retêm valores de usuário. Este artigo descreve várias abordagens para preservar os dados do usuário entre as solicitações.
Ver ou baixar o código de exemplo (como baixar)
Gestão do Estado
O estado pode ser armazenado usando várias abordagens. Cada abordagem é descrita mais adiante neste artigo.
Abordagem de armazenamento | Mecanismo de armazenamento |
---|---|
Biscoitos | Cookies HTTP. Pode incluir dados armazenados usando o código do aplicativo do lado do servidor. |
Estado da sessão | Cookies HTTP e código de aplicativo do lado do servidor |
TempData | Cookies HTTP ou estado da sessão |
Cadeias de caracteres de consulta | Cadeias de caracteres de consulta HTTP |
Campos ocultos | Campos de formulário HTTP |
HttpContext.Items | Código do aplicativo do lado do servidor |
Cache | Código do aplicativo do lado do servidor |
Gerenciamento de estado baseado em contexto SignalR/Blazor Server e HTTP
SignalR aplicativos não devem usar o estado da sessão e outras abordagens de gerenciamento de estado que dependem de um contexto HTTP estável para armazenar informações.
SignalR aplicações podem armazenar o estado de cada ligação em Context.Items
no hub. Para obter mais informações e abordagens alternativas de gerenciamento de estado para aplicativos Blazor Server, consulte ASP.NET Core Blazor state management.
Biscoitos
Os cookies armazenam dados entre pedidos. Uma vez que os cookies são enviados a cada pedido, o seu tamanho deve ser reduzido ao mínimo. Idealmente, apenas um identificador deve ser armazenado em um cookie com os dados armazenados pela aplicação. A maioria dos navegadores restringe cookie tamanho a 4096 bytes. Apenas um número limitado de cookies está disponível para cada domínio.
Como os cookies estão sujeitos a adulteração, eles devem ser validados pelo aplicativo. Os cookies podem ser eliminados pelos utilizadores e expirar nos clientes. No entanto, os cookies são geralmente a forma mais durável de persistência de dados no cliente.
Os cookies são frequentemente utilizados para personalização, onde o conteúdo é personalizado para um utilizador conhecido. O usuário só é identificado e não autenticado na maioria dos casos. O cookie pode armazenar o nome do usuário, o nome da conta ou o ID de usuário exclusivo, como um GUID. O cookie pode ser usado para acessar as configurações personalizadas do usuário, como a cor de fundo do site preferida.
Consulte o Regulamento Geral de Proteção de Dados da União Europeia (GDPR) quando emite cookies e lida com preocupações de privacidade. Para obter mais informações, consulte o suporte ao Regulamento Geral sobre a Proteção de Dados (RGPD) no ASP.NET Core.
Estado da sessão
O estado da sessão é um cenário ASP.NET Core para armazenamento de dados do usuário enquanto o usuário navega em um aplicativo Web. O estado da sessão usa um repositório mantido pelo aplicativo para persistir dados entre solicitações de um cliente. Os dados da sessão são apoiados por um cache e considerados dados efêmeros. O site deve continuar a funcionar sem os dados da sessão. Os dados críticos do aplicativo devem ser armazenados no banco de dados do usuário e armazenados em cache na sessão apenas como uma otimização de desempenho.
A sessão não é suportada em aplicativos
ASP.NET Core mantém o estado da sessão fornecendo um cookie ao cliente que contém uma ID de sessão. O ID da sessão cookie:
- É enviado para a aplicação com cada pedido.
- É usado pelo aplicativo para buscar os dados da sessão.
O estado da sessão exibe os seguintes comportamentos:
- A sessão cookie é específica para o navegador. As sessões não são compartilhadas entre navegadores.
- Os cookies de sessão são eliminados quando a sessão do navegador termina.
- Se uma cookie for recebida para uma sessão expirada, será criada uma nova sessão que usará a mesma sessão cookie.
- As sessões vazias não são mantidas. A sessão deve ter pelo menos um valor definido para persistir a sessão entre solicitações. Quando uma sessão não é mantida, uma nova ID de sessão é gerada para cada nova solicitação.
- O aplicativo mantém uma sessão por um tempo limitado após a última solicitação. O aplicativo define o tempo limite da sessão ou usa o valor padrão de 20 minutos. O estado da sessão é ideal para armazenar dados do usuário:
- Isso é específico para uma sessão específica.
- Onde os dados não exigem armazenamento permanente entre sessões.
- Os dados da sessão são excluídos quando a implementação do ISession.Clear é chamada ou quando a sessão expira.
- Não há nenhum mecanismo padrão para informar ao código da aplicação que um navegador cliente foi fechado ou quando a sessão cookie foi excluída ou expirou no cliente.
- Os cookies de estado de sessão não são marcados como essenciais por padrão. O estado da sessão não é funcional, a menos que o rastreamento seja permitido pelo visitante do site. Para obter mais informações, consulte suporte ao Regulamento Geral de Proteção de Dados (RGPD) no ASP.NET Core.
Advertência
Não armazene dados confidenciais no estado da sessão. O usuário pode não fechar o navegador e limpar a sessão cookie. Alguns navegadores mantêm cookies de sessão válidos nas janelas do navegador. Uma sessão pode não estar restrita a um único usuário. O próximo usuário pode continuar a navegar no aplicativo com a mesma sessão cookie.
O provedor de cache na memória armazena dados de sessão na memória do servidor onde o aplicativo reside. Num cenário de centro de dados:
- Use sessões persistentes para vincular cada sessão a uma instância de aplicação específica em um servidor específico. Serviço de Aplicativo do Azure usa Roteamento de Solicitação de Aplicativo (ARR) para impor sessões persistentes por padrão. No entanto, sessões adesivas podem afetar a escalabilidade e complicar as atualizações do aplicativo Web. Uma abordagem melhor é usar um cache distribuído Redis ou SQL Server, que não requer sessões adesivas. Para obter mais informações, consulte Cache distribuído no ASP.NET Core.
- A sessão cookie é encriptada através IDataProtector. A Proteção de Dados deve ser configurada corretamente para ler cookies de sessão em cada máquina. Para obter mais informações, consulte Visão geral da proteção de dados do ASP.NET Core e Provedores de armazenamento de chaves.
Configurar o estado da sessão
O pacote de Microsoft.AspNetCore.Session:
- É incluído implicitamente pelo quadro.
- Fornece middleware para gerenciar o estado da sessão.
Para habilitar o middleware de sessão, Startup
deve conter:
- Qualquer uma das memórias cache IDistributedCache. A implementação
IDistributedCache
é usada como um armazenamento de apoio para a sessão. Para obter mais informações, consulte Cache distribuído no ASP.NET Core. - Uma chamada para AddSession em
ConfigureServices
. - Uma chamada para UseSession em
Configure
.
O código a seguir mostra como configurar o fornecedor de sessão em memória com uma implementação padrão em memória 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();
});
}
}
O código anterior define um curto tempo limite para simplificar o teste.
A ordem do middleware é importante. Ligue UseSession
depois de UseRouting
e antes de UseEndpoints
. Consulte Middleware Ordering.
HttpContext.Session está disponível após a configuração do estado da sessão.
HttpContext.Session
não pode ser acessado antes que UseSession
tenha sido chamado.
Uma nova sessão cookie não pode ser criada depois de o aplicativo começar a gravar no fluxo de resposta. A exceção é registrada no log do servidor Web e não é exibida no navegador.
Carregar o estado da sessão de forma assíncrona
O provedor de sessão padrão no ASP.NET Core carrega registros de sessão do armazenamento de backup de IDistributedCache subjacente de forma assíncrona somente se o método ISession.LoadAsync for explicitamente chamado antes dos métodos TryGetValue, Setou Remove. Se LoadAsync
não for chamado primeiro, o registo de sessão subjacente será carregado de forma síncrona, o que poderá acarretar uma penalidade de desempenho à escala.
Para que as aplicações imponham esse padrão, envolva as implementações de DistributedSessionStore e DistributedSession com versões que lancem uma exceção se o método LoadAsync
não for chamado antes de TryGetValue
, Set
ou Remove
. Registre as versões encapsuladas no contêiner de serviços.
Opções de sessão
Para substituir os padrões de sessão, use SessionOptions.
Opção | Descrição |
---|---|
Cookie | Determina as configurações usadas para criar o cookie.
Name assume como padrão SessionDefaults.CookieName (.AspNetCore.Session ).
Path assume como padrão SessionDefaults.CookiePath (/ ).
SameSite adota SameSiteMode.Lax (1 ) como padrão.
HttpOnly assume como padrão true .
IsEssential assume como padrão false . |
IdleTimeout | O IdleTimeout indica por quanto tempo a sessão pode ficar ociosa antes que seu conteúdo seja abandonado. Cada sessão de acesso redefine o tempo limite. Esta definição aplica-se apenas ao conteúdo da sessão, não ao cookie. O padrão é 20 minutos. |
IOTimeout | A quantidade máxima de tempo permitida para carregar uma sessão da loja ou confirmá-la de volta à loja. Essa configuração pode se aplicar apenas a operações assíncronas. Esse tempo limite pode ser desativado usando InfiniteTimeSpan. O padrão é 1 minuto. |
A sessão usa um cookie para rastrear e identificar solicitações de um único navegador. Por padrão, esse cookie é chamado .AspNetCore.Session
e usa um caminho de /
. Como o padrão cookie não especifica um domínio, ele não é disponibilizado para o script do lado do cliente na página (porque o padrão de HttpOnly é true
).
Para alterar os padrões de sessão cookie, 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();
}
O aplicativo usa a propriedade IdleTimeout para determinar por quanto tempo uma sessão pode ficar ociosa antes que seu conteúdo no cache do servidor seja abandonado. Esta propriedade é independente da validade do cookie. Cada solicitação que passa pelo Middleware de Sessão reinicia o tempo de espera.
O estado da sessão é sem bloqueio . Se duas solicitações simultaneamente tentarem modificar o conteúdo de uma sessão, a última solicitação substituirá a primeira.
Session
é implementado como uma sessão coerente, o que significa que todos os conteúdos são armazenados em conjunto. Quando duas solicitações procuram modificar valores de sessão diferentes, a última solicitação pode substituir as alterações de sessão feitas pela primeira.
Definir e obter valores de sessão
O estado da sessão é acessado a partir de uma classe Razor Pages PageModel ou classe MVC Controller com HttpContext.Session. Esta propriedade é uma implementação do tipo ISession.
A implementação ISession
fornece vários métodos de extensão para definir e recuperar valores inteiros e de cadeia de caracteres. Os métodos de extensão estão no namespace Microsoft.AspNetCore.Http.
ISession
métodos de extensão:
- Get(ISession, String)
- GetInt32(ISession, String)
- GetString(ISession, String)
- SetInt32(ISession, String, Int32)
- SetString(ISession, String, String)
O exemplo a seguir recupera o valor da sessão para a chave IndexModel.SessionKeyName
(_Name
no aplicativo de exemplo) em uma página Razor Pages:
@page
@using Microsoft.AspNetCore.Http
@model IndexModel
...
Name: @HttpContext.Session.GetString(IndexModel.SessionKeyName)
O exemplo a seguir mostra como definir e obter um inteiro e uma cadeia de caracteres:
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 os dados da sessão devem ser serializados para habilitar um cenário de cache distribuído, mesmo ao usar o cache na memória. Os serializadores de cadeia de caracteres e inteiros são fornecidos pelos métodos de extensão de ISession. Tipos complexos devem ser serializados pelo usuário usando outro mecanismo, como JSON.
Use o seguinte código de exemplo 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);
}
}
O exemplo a seguir mostra como definir e obter um objeto serializável com a classe SessionExtensions
:
// Requires SessionExtensions from sample download.
if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
{
HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}
TempData
ASP.NET Core expõe as Razor Pages TempData ou Controller TempData. Esta propriedade armazena os dados até que sejam lidos em outra solicitação. Os métodos Keep(String) e Peek(string) podem ser usados para examinar os dados sem exclusão no final da solicitação.
Conservar marca todos os itens do dicionário para conservação.
TempData
é:
- Útil para redirecionamento quando os dados são necessários para mais de uma única solicitação.
- Implementado por provedores de
TempData
usando cookies ou estado de sessão.
Exemplos de TempData
Considere a seguinte página que cria um 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");
}
}
A página a seguir exibe TempData["Message"]
:
@page
@model IndexModel
<h1>Peek Contacts</h1>
@{
if (TempData.Peek("Message") != null)
{
<h3>Message: @TempData.Peek("Message")</h3>
}
}
@*Content removed for brevity.*@
Na marcação anterior, no final da solicitação, TempData["Message"]
não é apagado porque Peek
é utilizado. Recarregar a página exibe o conteúdo do TempData["Message"]
.
A marcação a seguir é semelhante ao código anterior, mas usa Keep
para preservar os dados no final da solicitação:
@page
@model IndexModel
<h1>Contacts Keep</h1>
@{
if (TempData["Message"] != null)
{
<h3>Message: @TempData["Message"]</h3>
}
TempData.Keep("Message");
}
@*Content removed for brevity.*@
Navegar entre as páginas IndexPeek e IndexKeep não excluirá TempData["Message"]
.
O código a seguir exibe TempData["Message"]
, mas no final da solicitação, TempData["Message"]
é excluído:
@page
@model IndexModel
<h1>Index no Keep or Peek</h1>
@{
if (TempData["Message"] != null)
{
<h3>Message: @TempData["Message"]</h3>
}
}
@*Content removed for brevity.*@
Fornecedores TempData
O provedor TempData baseado em cookieé usado por padrão para armazenar TempData em cookies.
Os dados cookie são criptografados usando IDataProtector, codificados com Base64UrlTextEncodere, em seguida, fragmentados. O tamanho máximo cookie é inferior a 4096 bytes devido à criptografia e fragmentação. Os dados cookie não são compactados porque a compactação de dados criptografados pode levar a problemas de segurança, como ataques CRIME e BREACH. Para obter mais informações sobre o provedor TempData baseado em cookie, consulte CookieTempDataProvider.
Escolha um provedor TempData
A escolha de um provedor TempData envolve várias considerações, como:
- O aplicativo já usa o estado da sessão? Nesse caso, usar o provedor TempData de estado de sessão não tem custo adicional para o aplicativo além do tamanho dos dados.
- O aplicativo usa o TempData apenas com moderação para quantidades relativamente pequenas de dados, até 500 bytes? Em caso afirmativo, o provedor cookie TempData adiciona um pequeno custo a cada solicitação que carrega TempData. Caso contrário, o provedor TempData do estado da sessão pode ser benéfico para evitar a ida e volta de uma grande quantidade de dados em cada solicitação até que o TempData seja consumido.
- A aplicação é executada num conjunto de servidores em vários servidores? Nesse caso, não é necessária nenhuma configuração adicional para usar o provedor TempData cookie fora da Proteção de Dados (consulte Visão Geral da Proteção de Dados do ASP.NET Core e Provedores de armazenamento de chaves).
A maioria dos clientes da Web, como navegadores da Web, impõe limites ao tamanho máximo de cada cookie e ao número total de cookies. Ao usar o provedor cookie TempData, verifique se o aplicativo não excederá esses limites. Considere o tamanho total dos dados. Considere aumentos do tamanho de cookie devido à criptografia e fragmentação.
Configurar o provedor TempData
O provedor TempData baseado em cookieestá habilitado por padrão.
Para habilitar o provedor TempData baseado em sessão, use o método de extensão AddSessionStateTempDataProvider. Apenas uma chamada para AddSessionStateTempDataProvider
é necessária:
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();
});
}
Cadeias de caracteres de consulta
Uma quantidade limitada de dados pode ser passada de uma solicitação para outra, adicionando-a à cadeia de caracteres de consulta da nova solicitação. Isso é útil para capturar o estado de forma persistente que permite que links com o estado incorporado sejam compartilhados por e-mail ou redes sociais. Como as cadeias de caracteres de consulta de URL são públicas, nunca use cadeias de caracteres de consulta para dados confidenciais.
Além do compartilhamento não intencional, a inclusão de dados em cadeias de caracteres de consulta pode expor o aplicativo a ataques de CSRF (Cross-Site Request Forgery). Qualquer estado de sessão preservado deve proteger contra ataques CSRF. Para obter mais informações, consulte Prevenir ataques de falsificação de solicitação entre sites (XSRF/CSRF) no ASP.NET Core.
Campos ocultos
Os dados podem ser salvos em campos de formulário ocultos e postados novamente na próxima solicitação. Isso é comum em formulários de várias páginas. Como o cliente pode potencialmente adulterar os dados, o aplicativo sempre deve revalidar os dados armazenados em campos ocultos.
HttpContext.Items
A coleção HttpContext.Items é usada para armazenar dados durante o processamento de uma única solicitação. O conteúdo da coleção é descartado após o processamento de uma solicitação. A coleção Items
é frequentemente usada para permitir que componentes ou middleware se comuniquem quando operam em diferentes pontos no tempo durante uma solicitação e não têm uma maneira direta de passar parâmetros.
No exemplo a seguir, middleware adiciona isVerified
à coleção 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"]}");
});
});
}
Para middleware usado apenas em um único aplicativo, chaves de string
fixas são aceitáveis. O middleware compartilhado entre aplicativos deve usar chaves de objeto exclusivas para evitar colisões de chaves. O exemplo a seguir mostra como usar uma chave de objeto exclusiva definida em uma classe 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>();
}
}
Outro código pode acessar o valor armazenado em HttpContext.Items
usando a chave exposta pela classe middleware:
HttpContext.Items
.TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey,
out var middlewareSetValue);
SessionInfo_MiddlewareValue =
middlewareSetValue?.ToString() ?? "Middleware value not set!";
Essa abordagem também tem a vantagem de eliminar o uso de cadeias de caracteres de chave no código.
Cache
O cache é uma maneira eficiente de armazenar e recuperar dados. O aplicativo pode controlar o tempo de vida dos itens armazenados em cache. Para obter mais informações, consulte cache de resposta no ASP.NET Core.
Os dados armazenados em cache não estão associados a uma solicitação, usuário ou sessão específica. Não armazene em cache dados específicos do usuário que possam ser recuperados por outras solicitações do usuário.
Para armazenar em cache dados de todo o aplicativo, consulte Cache na memória no ASP.NET Core.
Erros comuns
"Não é possível resolver o serviço para o tipo 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' ao tentar ativar 'Microsoft.AspNetCore.Session.DistributedSessionStore'."
Isso geralmente é causado por não configurar pelo menos uma implementação
IDistributedCache
. Para obter mais informações, consulte Cache distribuído no ASP.NET Core e Cache na memória no ASP.NET Core.
Se o middleware de sessão não conseguir persistir uma sessão:
- O middleware registra a exceção e a solicitação continua normalmente.
- Isso leva a um comportamento imprevisível.
O middleware de sessão pode falhar ao persistir uma sessão se o armazenamento de backup não estiver disponível. Por exemplo, um usuário armazena um carrinho de compras na sessão. O usuário adiciona um item ao carrinho, mas a confirmação falha. O aplicativo não sabe sobre a falha, então relata ao usuário que o item foi adicionado ao carrinho, o que não é verdade.
A abordagem recomendada para verificar se há erros é chamar await feature.Session.CommitAsync
quando o aplicativo terminar de gravar na sessão.
CommitAsync lança uma exceção se o armazenamento subjacente não estiver disponível. Se CommitAsync
falhar, o aplicativo poderá processar a exceção.
LoadAsync é lançado nas mesmas condições quando o armazenamento de dados não está disponível.