asp.netredisazure-web-app-servicesession-cookiesazure-deployment-slots

How do i retain my session after a deploymentslot swap using asp.net and redis cache


I have an asp.net application (.net version 6) configured like this:

var redisConnectionString = "fakestring";

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = redisConnectionString;
});

builder.Services.AddSession(options =>
{
    options.Cookie.Name = "fakecookiename";
    options.IdleTimeout = TimeSpan.FromMinutes(builder.Configuration.GetValue<int>("SessionDefaults:IdleTimeoutInMinutes"));
    options.Cookie.SameSite = SameSiteMode.None;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});

I use the latest StackExchange.Redis nuget package (2.7.33) after numerous issues losing the Redis connection when swapping slots up to 20 minutes before stable again.

Now my Redis connection seems stable when swapping but a new issue arises.

After swapping slots (all application settings aren't slots specific) my browser gets a new Session Cookie. So i'm actually losing my session resulting in Session Expired exceptions in my frontend application.

Is there a way to retain the session cookie after a deploymentslot swap?

Thanks already for you help.

Kind Regards


Solution

  • I tried your code and was able to retain the session token successfully after the deployment slot swap.

    After swapping slots (all application settings aren't slots specific) my browser gets a new Session Cookie. So I'm actually losing my session resulting in Session Expired exceptions in my frontend application.

    To avoid above issue

    This is my Program.cs:

    
    using Microsoft.AspNetCore.Builder;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using StackExchange.Redis;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Caching.StackExchangeRedis;
    using Microsoft.AspNetCore.DataProtection;
    using System.Runtime.Intrinsics.X86;
    
    var builder = WebApplication.CreateBuilder(args);
    var configuration = builder.Configuration;
    
    var fakeRedisConnectionString = "fakestring";
    builder.Services.AddStackExchangeRedisCache(options =>
    {
       options.Configuration = fakeRedisConnectionString;
    });
    
    builder.Services.AddSession(options =>
    {
       options.Cookie.Name = "fakecookiename";
       options.IdleTimeout = TimeSpan.FromMinutes(builder.Configuration.GetValue<int>("SessionDefaults:IdleTimeoutInMinutes"));
       options.Cookie.SameSite = SameSiteMode.None; 
       options.Cookie.SecurePolicy = CookieSecurePolicy.Always; 
    });
    
    var redisConnectionString = configuration.GetConnectionString("RedisConnection");
    builder.Services.AddStackExchangeRedisCache(options =>
    {
       options.Configuration = redisConnectionString;
       options.InstanceName = "YourAppInstance"; 
    });
    
    builder.Services.AddSession(options =>
    {
       options.Cookie.Name = ".YourApp.Session"; 
       options.IdleTimeout = TimeSpan.FromMinutes(configuration.GetValue<int>("SessionDefaults:IdleTimeoutInMinutes"));
       options.Cookie.SameSite = SameSiteMode.Strict; 
       options.Cookie.SecurePolicy = CookieSecurePolicy.Always; 
       options.Cookie.HttpOnly = true; 
       options.Cookie.IsEssential = true; 
    });
    
    builder.Services.AddDataProtection()
       .PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect("your redisconnection string"),"DataProtection-Keys");
    
    var app = builder.Build();
    app.UseSession();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
       endpoints.MapGet("/", async context =>
       {
           context.Session.SetString("TestKey", "TestValue");
           await context.Response.WriteAsync("Session value set.");
       });
       endpoints.MapGet("/get", async context =>
       {
           var value = context.Session.GetString("TestKey");
           await context.Response.WriteAsync($"Session value: {value}");
       });
    });
    
    app.Run();
    
    

    Appsettings.json:

    {
        "ConnectionStrings": {
            "RedisConnection": "redis connection string"
        },
        "SessionDefaults": {
            "IdleTimeoutInMinutes": 20
        }
    }
    

    Local output:

    enter image description here

    Output after deployment : enter image description here

    Here's the output after slot swapping:

    enter image description here