Announcing ASP.NET Session State Provider for Redis Preview Release

Announcing ASP.NET Session State Provider for Redis Preview Release

Rate This
  • Comments 56

Today, we are pleased to announce a preview release of ASP.NET Session State Provider for Redis. You can use it with your own Redis server or the newly announce Microsoft Azure Redis Cache (Preview).

What is Redis

Redis is an open source, BSD licensed, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets. It’s getting popular in the web development community as a session state store because of its simplicity, rich data structure support and outstanding performance.

Installing

You can download this preview release of ASP.NET session state provider for Redis (https://www.nuget.org/packages/Microsoft.Web.RedisSessionStateProvider) from NuGet gallery by running this command

Install-Package Microsoft.Web.RedisSessionStateProvider -Pre

Get started

Get Redis

Before using the session state provider for Redis, you need to (of course) get a Redis server. There are a lot of ways to get a Redis server depends on your OS and whether your app is in the cloud or on-prem. Today, I’m going to show you two:

In the cloud – Microsoft Azure Redis Cache (Preview)

The newly announced Microsoft Azure Redis Cache (Preview) provides your Redis host in Azure. It’s super easy to use. Just follow this get started article to get one in minutes. After it’s done, get hold of the host name and access key since we need to use them later.

On-prem – Redis on Windows

The Redis project doesn’t directly support Windows. However, Microsoft Open Technologies, Inc. develops and maintains a high quality Windows port. You can install it from NuGet, Chocolatey or download it directly from the project github repository. After the installation, you can find the following two .exe files that we are interested at:

  • redis-server.exe: Run this .exe file and you will have a Redis server running on your machine.
  • redis-cli.exe: We will use this as a command line tool later to check the data in your Redis server. Note: we’ll use it to check the data in Azure Redis Cache as well.

Create a simple project

To get started,

  • Create an ASP.NET Web Application in Visual Studio.
  • Add RedisSessionStateProvider NuGet package which will do the following:
    • Add references to the ASP.NET session state provider for Redis assembly and its dependencies.
    • Add the following configuration to system.web section in Web.config file.
Code Snippet
  1. <sessionState mode="Custom" customProvider="MySessionStateStore">
  2.   <providers>
  3.     <!--
  4.       <add name="MySessionStateStore"
  5.         host = "127.0.0.1" [String]
  6.         port = "" [number]
  7.         accessKey = "" [String]
  8.         ssl = "false" [true|false]
  9.         throwOnError = "true" [true|false]
  10.         retryTimeoutInMilliseconds = "0" [number]
  11.       />
  12.     -->
  13.     <add name="MySessionStateStore" type="Microsoft.Web.Redis.RedisSessionStateProvider" host="127.0.0.1" accessKey="" ssl="false" />
  14.   </providers>
  15. </sessionState>
  • If you are using Azure Redis Cache, modify host and accessKey with the values you get when you create the Redis Cache. If you are using local Redis server, leave them as it is.
  • Add line 9 shown below to the Login method in AccountController.cs to add the login time to session.
Code Snippet
  1. public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
  2. {
  3.     if (ModelState.IsValid)
  4.     {
  5.         var user = await UserManager.FindAsync(model.Email, model.Password);
  6.         if (user != null)
  7.         {
  8.             await SignInAsync(user, model.RememberMe);
  9.             Session["loginTime"] = DateTime.Now.ToString(); // Add this line
  10.             return RedirectToLocal(returnUrl);
  11.         }
  12.         else
  13.         {
  14.             ModelState.AddModelError("", "Invalid username or password.");
  15.         }
  16.     }
  17.  
  18.     // If we got this far, something failed, redisplay form
  19.     return View(model);
  20. }
  • Run the project.
  • Sign up an account and log in with it.
  • Run redis-cli.exe from command line to connect to the Redis server and check out the session data by running the following commands and you’ll see the session data is successfully stored in Redis. If you are running Redis server locally, you don’t need the -h (host) or -a (password) parameter. (You see the hex data because we convert the value into bytes before putting it into Redis). For more information about redis-cli, please refer to http://redis.io/commands.

image

Protect your data Azure Redis Cache access key when using redis-cli.exe

When you use redis-cli.exe to connect to your Azure Redis Cache, since it doesn’t support SSL by default, the data and more importantly the access key are sent via TCP in clear text. To protect them, follow the instructions below to set up a SSL proxy on your machine for redis-cli.exe.

  • Download and install stunnel.
  • Open stunnel GUI Start from your start screen
  • Click Menu –> Configuration –> Edit Configuration. This will open the stunnel configuration file.
  • Go to the section named as “Example SSL client mode services” and add the following configuration.

Code Snippet
  1. [redis-cli]
  2. client = yes
  3. accept = 127.0.0.1:6380
  4. connect = azrocks.redis.cache.windows.net:6380

  • Click Menu –> Configuration –> Reload Configuration. This will let stunnel load the new configuration.
  • Connect to your Azure Redis Cache using the following command

redis-cli.exe -p 6380 –a <your access key>

Now, you are having the TCP traffic from redis-cli.exe via a local SSL proxy provided by stunnel.

Configuration details

Now let’s look a little bit deeper into the settings you can use on this session state provider and how they will change its behaviors.

How to connect to Redis server

These are the settings that configure connections to Redis server:

  • host: The IP address or host name of your Redis server. By default it’s localhost.
  • port: The port of your Redis server. By default it’s 6379 for non-ssl and 6380 for ssl (if you are using Azure Redis Cache). 
  • accessKey: The password of your Redis server when Redis authorization is enabled. By default is empty, which means the session state provider won’t use any password when connecting to Redis server. If your Redis server is in a publicly accessible network, like Azure Redis Cache, be sure to enable Redis authorization to improve security.
  • ssl: Whether to connect to Redis server via ssl or not. By default is false because Redis doesn’t support SSL out of the box. If you are using Azure Redis Cache which supports SSL out of the box,  be sure to set this to true to improve security.

How session state provider should behave

throwOnError

When we talk to developers about the current available ASP.NET session state providers, one of the top complaints is that with the current available session state providers, if an error occurs during a session operation, the session state provider will throw an exception, which will blow up the entire application.

We want to address this in a way that it won’t surprise existing ASP.NET session state provider users and at the same time, provide the ability to opt-in the advanced behaviors. To do this, we introduced the following setting in this session state provider:

  • throwOnError: Whether or not to throw an exception when some error occurs. The default is true.

As you can see, the default behavior will still throw an exception when some error occurs. This is consistent with the other ASP.NET session state providers we provide so there won’t be any surprise and your existing code will just work.

If you set throwOnError to false, then instead of throwing an exception when some error occurs, it will fail silently. If you need to check if there was some error and if there was one, what the exception was, you can check it using this static property

Code Snippet
  1. Microsoft.Web.Redis.RedisSessionStateProvider.LastException

This is really cool because

  • If you have some existing applications using some existing session state provider, you don’t need to change any code but get away from blowing up the entire application for free.
  • You can explicitly check for errors if there were any.

retryTimeoutInMilliseconds

We also want to provide some retry logic to simplify the case where some session operation should retry on failure because of things like network glitch. At the same time, we also heard from developers that they want the ability to control the retry timeout or opt-out of retry entirely because they know retry won’t solve the issue in their cases. To do this, we introduced the following setting in this session state provider:

  • retryTimeoutInMilliseconds: How long it will retry when an operation fails. Default is 0, meaning no retry.

If you set retryTimeoutInMilliseconds to a number, say 5000, then when a session operation fails, it will retry for 5000 milliseconds before treating it as an error. So if you would like to have the session state provider to apply this retry logic for you, you can simply configure the timeout. The first retry will happen after 20 milliseconds since that is good enough in most cases when a network glitch happens. After that, it will retry every 1 second till it times out. Right after the time out, it will retry one more time to make sure that it won’t cut off the timeout by (at most) 1 second.

If you don’t think you need retry (like when you are running the Redis server on the same machine as your application) or if you want to handle the retry logic yourself, you can just leave it to the default value 0.

Conclusion

We are really excited about this release. Give it a try and let us know what you think!

Leave a Comment
  • Please add 6 and 8 and type the answer here:
  • Post
  • Is this using the same "lock the session" for each request that the sql session provider does? Or will this allow more than one request to execute at the same time?

  • @Paul => It does same as sql session provider - lock the session for writing.

  • It's very great! I have some questions

    How it saves items into redis? Based from HGETALL from screenshot each item saved as separate item in the same hashset? Does each item loads and serializes independently on others or all of them loaded in one request to Redis? What Redis provider it uses underhood? ServiceStack\BookSlave\ or some custom implementations?

  • @ Sergey Litvinov

    How it saves items into redis?

    => It saves single session into Redis as single hash.

    For example, I have session with sesion id = "session-id-1". I have stored "key1 = val1" and "key2=val2" inside session. If you do HGETALL session-id-1_Data you will get both keys and values.

    Does each item loads and serializes independently on others or all of them loaded in one request to Redis?

    => All values for given session will be loaded during fetch cycle of session inside GetItem/GetItemExclusive using HGETALL. But they are de-serialized independently one after another. But only those which are modified will be written back during SetAndReleaseItemExclusive.

    What Redis provider it uses underhood?

    => StackExchange.Redis

  • This is really help full. I also refer http://www.nerdcorelabs.com/ if i get any problems

  • It misses a simple way to share a redis cache between multiple websites. A key prefix setting in the provider could resolve this.

  • @Joanna Robinson: Thank you, if you need any help or have any question post here.

    @styx31: Can you explain some more about what you mean by "A key prefix setting in the provider could resolve this."  

  • Where is the source code?

  • @Siddharth Chatrola Currently, the provder use the session id (random chars + data) as the RedisKey in the cache.

    If two websites wants to share the redis cache instance for session storage, it could be better to prefix the session id with the applicationname attribute of the provider.

    See msdn.microsoft.com/.../ms178587.aspx paragraph "ApplicationName".

  • The ability to provide a database id could be also great.

  • @ styx, @styx31 = Thanks for the feedback.

    I am working on following two and will publish new NuGet and will let you know configuration details.

    1) RedisKey as application name + session id.

    2) Ability to provide a database id.

  • We already have such provider here: www.nuget.org/.../RedisAspNetProviders. What is the difference?

  • @alex-simonov: There are many differences in actual implementation but just to mention few bigger once SSL support, throwOnError, retryTimeoutInMilliseconds etc.

  • @Siddharth Chatrola, where is source code hosted?

  • @Siddharth Chatrola, I've opened dll with Reflector and found a bug. If I modify a state of a mutable object stored in session then these changes will not be saved in redis because this provider can not track changes of state of stored mutable objects.

Page 1 of 4 (56 items) 1234