ASP .NET Core - Trabalhando com Session - I


Hoje vamos entender como funciona e como podemos trabalhar com Session na ASP .NET Core 3.1.

A primeira coisa que você tem que saber sobre o objeto Session na ASP .NET Core é que ele é totalmente diferente do objeto Session da ASP .NET MVC ou do Web Forms.

Na ASP.NET MVC a configuração era feita através de uma combinação do arquivo web.config, o arquivo Global.asax e das classes na pasta Startup.  Na ASP.NET Core MVC Core toda a configuração é feita em um só lugar : na classe Startup do projeto.

Isso centraliza a configuração pois você deve definir várias opções como escolher quais serviços deseja usar e qual middleware deseja no pipeline de processamento do ASP.NET.
 
A ASP.NET Core mantém o estado da sessão fornecendo um cookie ao cliente que contém uma ID de sessão a seguir o ID da sessão do cookie:

O estado da sessão exibe os seguintes comportamentos:

Configurando o Session

Para configurar o Session usamos o pacote Microsoft.AspNetCore.Session que esta incluído por padrão na ASP .NET Core fornecendo o middleware para gerenciar o estado da sessão.

Para habilitar o middleware da sessão a classe Startup do projeto deve conter:

O código a seguir mostra como configurar o provedor de sessão na memória com uma implementação na memória padrão 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();
        });
    }
}

No código acima destacamos o código necessário para configurar a Session em azul onde:

1- No método ConfigureServices definimos o código abaixo:

        services.AddDistributedMemoryCache();

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

onde:

No método Configure definimos o uso da Session e aqui cabe destacar que :

Assim agora HttpContext.Session está disponível após a configuração do estado da sessão e não pode ser acessado antes que UseSession tenha sido chamado.

Você deve atentar para o fato de que uma nova sessão com um novo cookie de sessão não pode ser criada depois que o aplicativo começou a gravar no fluxo de resposta. A exceção é registrada no log do servidor da web e não é exibida no navegador.

Além disso o provedor de sessão padrão na ASP.NET Core carrega registros de sessão a partir do IDistributedCache subjacente de forma assíncrona apenas se o método ISession.LoadAsync for explicitamente chamado antes dos métodos TryGetValue, Set ou 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 um desempenho menos otimizado.

Definindo e obtendo valores da Session

O estado da sessão é acessado a partir de uma classe Razor Pages PageModel ou uma classe MVC Controller via HttpContext.Session e esta propriedade é uma implementação de ISession.

A implementação de ISession oferece vários métodos de extensão para definir e recuperar valores inteiros e de string. Os métodos de extensão estão no namespace Microsoft.AspNetCore.Http e os principais são:

No trecho de  código a seguir estamos atribuindo e recuperando valores da sessão usando os métodos acima:

 public class HomeController : Controller  
 {  
       const string SessionNome = "Nome";  
       const string SessionEmail = "Email";  
       const string SessionIdade = "Idade";

       public IActionResult Index()  
       {  
            HttpContext.Session.SetString(SessionNome, "Macoratti");  
            HttpContext.Session.SetString(SessionEmail, "macoratti@yahoo.com");  
            HttpContext.Session.SetInt32(SessionIdade, 55);  
            return View();  
        }    
       public IActionResult About()  
       {  
            ViewBag.Nome = HttpContext.Session.GetString(SessionNome);  
            ViewBag.Email = HttpContext.Session.GetString(SessionEmail);  
            ViewBag.Idade = HttpContext.Session.GetInt32(SessionIdade);
            ViewData["Message"] = "Asp.Net Core !!!.";  
            return View();  
        }  
   }  

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. Serializadores de string e inteiros são fornecidos pelos métodos de extensão de ISession. Os 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);
    }
}

No exemplo a seguir temos como definir e obter um objeto serializável com a classe SessionExtensions:

if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
{
    HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}

Usando HttpContext.Items

A coleção HttpContext.Items pode ser 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 de itens é geralmente usada para permitir que componentes ou middleware se comuniquem quando operam em diferentes momentos durante uma solicitação e não têm uma maneira direta de passar parâmetros.

No exemplo a seguir, o middleware adiciona isVerified à coleção de itens:

public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    app.UseRouting();
    app.Use(async (context, next) =>
    {
        logger.LogInformation($"Antes de configurar: Verificado: {context.Items["isVerified"]}");
        context.Items["isVerified"] = true;
        await next.Invoke();
    });
    app.Use(async (context, next) =>
    {
        logger.LogInformation($"Proxima: Verificado: {context.Items["isVerified"]}");
        await next.Invoke();
    });
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync($"Verificado: {context.Items["isVerified"]}");
        });
    });
}

E assim temos uma visão dos principais conceitos envolvidos no uso do objeto Session. Para mais detalhes consulte a documentação.

Na próxima parte do artigo vamos por o conceito de Session na prática criando um carrinho de compras.

E a vida eterna é esta: que te conheçam a ti, o único Deus verdadeiro, e a Jesus Cristo, a quem enviaste.
João 17:3

Referências:


José Carlos Macoratti