title: Sharing session over multiple servers with redis
body: <p>I'm implementing a distributed redis cache in .NET Core to be shared among multiple .NET Core services in a microservice environment.  The microservices are on multiple servers behind a load-balancer on IIS.  The redis cache will be used to temporarily hold data related to individual users.  The redis server will be hosted internally.  I already have a cookie used for external authentication (AuthCookie), but I don't use Identity or Session as the user is expected to be logged in. I just send the AuthCookie to my authentication service, it authenticates and I fill my ClaimsPrincipal with the results.</p>
  
  <p>Since my cache will be user specific, I thought it would be a good idea to utilize .Net Session with a redis distributed cache backing.  I want to use AuthCookie as the key, but it fails because it doesn't know how to decrypt it, which sucks.  Therefore, I have to have a second, .net session specific cookie.  The problem is, the session isn't working across servers on my load balancer, even with persisting my keys. Here's a simple version of my set up:</p>
  
  <pre><code>public void ConfigureServices(IServiceCollection services)
  {
      var host = "127.0.0.1";
      var port = "6379";
      var conn = $"{host}:{port}";
      var redis = ConnectionMultiplexer.Connect(conn);
  
      services.AddDataProtection().PersistKeysToRedis(redis, "DataProtection-Keys");
  
      services.AddDistributedRedisCache(options =&gt;
      {
          options.Configuration = conn;
          options.InstanceName = "master";
      });
      services.AddSession(options =&gt; options.CookieName = "NetSession");
      services.AddMvc();
  }
  
  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  {
      app.UseSession();
      app.UseMvc();
  }
  
  public class RedisController : Controller
  {
      public string Get(string key)
      {
          return HttpContext.Session.GetString(key);
      }
  
      public string Post([FromBody] CacheData data)
      {
          HttpContext.Session.SetString(data.Key, data.Value);
          return $"Added {data.Key} with {data.Value}";
      }
  }
  </code></pre>
  
  <p>This works fine on one server, but setting 3 instances of it up on my load balancer won't work.  I call the load-balancer, it sets a key on server A, redis will show as masterSOMEGUID, and a long "NetSession" cookie will be returned.  I call get on the load-balancer, server B picks it up, "NetSession" is sent, but when trying to find the key it generates a different GUID and can't find it.  If I hit server A again it will find it no problem.  I can't figure out what I'm doing wrong.</p>
  
  <p>A separate solution I've found is to not use Session and just use IDistributedCache with the AuthCookie that's already on the requests.</p>
  
  <pre><code>public class RedisController : Controller
  {
      private readonly IDistributedCache _cache;
      public RedisController(IDistributedCache cache)
      {
          _cache = cache
      }
      public string Get(string key)
      {
          return _cache.GetString($"{HttpContext.Request.Cookies["NetSession"]}{key}");
      }
  
      public string Post([FromBody] CacheData data)
      {
         _cache.SetString($"{HttpContext.Request.Cookies["NetSession"]}{data.Key}", data.Value);
          return $"Added {data.Key} with {data.Value}";
      }
  }
  </code></pre>
  
  <p>This obviously creates a lot more entries on the redis store.  Is it bad form to do it this way?  It should be noted that I won't be storing user details, just user responses and other reusable information.</p>