ASP.NET Session State Management with Redis (Local Server Farm Testing)

What is Redis?

Redis is an open source key value data structure store. keys can be strings, hashes, lists, sets, sorted sets etc. This in memory data store is broadly used in session state storing and caching.

Why Redis for session state storing?

If you are developing web applications for big companies, possibilities are your application is hosted on multiple servers. To be frank that is actually true. In some cases, for example, you may want to provide a backup server if your main server fails. In other cases, for example you may want to decrease the requests load on one of your server and rather distribute them across multiple servers. So you get the point right? We will configure IIS to balance load across multiple servers. Don’t worry about the servers because I’ll configure my localhost with different port numbers to act as multiple server instances.

Now there is a catch in doing that! Suppose as a user I’m sending requests through your web application, you have a load balancer configured on top of your backend servers which can route incoming requests to one of your servers but you don’t know exactly which one since it depends on the state of your servers (load on a server/ is server up and running?). Again suppose in your app you have the session storing mechanism configured. For example, in your e-commerce web application you may want to store the added items to the cart through sessions. This is a real life scenario because you don’t want your user to lose all the added items if he/she accidently closes the browser window. You can persist those items for a limited amount of time in sessions so that user doesn’t have to start again from the beginning. So sessions are good! Right?

Anyways since we have multiple servers, sessions will be lost if something goes wrong. For example, you accidently closed the browser window while adding items to the cart. So, when you again open your browser and go to the same application URL, your request may or may not be routed to the same server which you were in the last browsing session. It may also be the fact that by the next time you are requesting to the application, the previous server dies and routed your request to a backup server. So in both cases you are doomed!

Radis comes to rescue us from this kind of situations! Since it is an in-memory data store, its sits on the load balancing server. Requests came into the load balancer where Redis is used to store the sessions. Again when a next request comes in the previous sessions can be found in the load balancer. So there are no worries of losing sessions. May be a simple diagram can clear you mind.

So in our server farm we have four servers among which one is a load balancer or sometimes we call it the staging server. All the requests came into the staging server then it is bypassed to one of the connected servers where the actual instances of our web application is.

Creating local server farm

To create local server farm, first you have to configure IIS (not IIS express that comes with visual studio) on your machine. Configuring IIS is easy. Just follow the steps below,

  • Go to Control Panel > Programs and Features
  • Click on “Turn Windows features on or off” from right panel
  • Select “Internet Information Service” and expand the node
  • Select the node “World Wide Web Services” > Application Deployment Features > ASP.NET 4.5 (ASP.NET 4.6 on Windows 10)
  • Click OK to install IIS on Windows 7/8/8.1/10

After installing a reboot may be required. From start menu open Internet Information Services (IIS) Manager.

To be able to create server farm from IIS manger you will need an extension. You can use Web Platform Installer and download a whole bunch of extensions from there. For now, we only need Application Request Routing (ARR) extension for IIS

Creating servers for server farm

Now we have to create local servers for our server farm. Since we are using different ports on localhost to act as multiple servers, we have to include their address in the windows host files. Add entry to the host file (C:\Windows\System32\drivers\etc\host) for three different servers i.e. load balancer (staging server in the diagram), server-a, server-b.

As you can see, we have configured three server addresses against localhost (127.0.0.1). Now to distinguish between them, we have to bind ports against them. Go to IIS manager, right click on the “Sites” node and select “Add Website”. Add three sites i.e. load balancer, server-a and server-b. Use 9000 for the load balancer whereas 9001 is for server-a and 9002 is for server-b. Here is a little screenshot on how I configured and added server-a.

If you added all the sites you should have the sites list like this,

Time to add the servers to the server farm. From IIS manager right click on the server farm node and select “Create Server Farm”.

Give your server farm a name (redis-testing-farm).

On the next page add your two servers (www.redis-testing-server-a.com, www.redis-testing-server-a.com ) with their respective http ports i.e. 9001 and 9002. Finish the step and click on the “No” button when rewrite rules window pops up.

Defining URL rewrite rules

We have to define the URL rewrite rules. Just follow the steps below,

  • On root node select URL Rewrite

  • Click “Add Rule” from right action bar and select blank rule

  • Give a name to your rule (redis-testing-farm-rule)
  • Type ( .* ) in pattern
  • Expand Condition node and add two conditions


  • Condition input

    Check if input string

    Pattern

    {HTTP_HOST}

    Matches the pattern

    (www\.|^)redis-testing-server-staging.com

    {SERVER_PORT}

    Matches the pattern

    9000

  • Expand the “Action” node
    • Select “Route to Server Farm” from action type dropdown
    • Check “Stop processing of subsequent rules”
    • Apply rules

  • Select redis-testing-farm and go to “Load Balance” option
    • Select “Weighted round robin”
    • Apply

  • Again select redis-testing-farm and go to “Server Affinity”
    • Select “Client Affinity”
    • Apply

We have selected round robin as load balancer algorithm. It will evenly distribute your incoming requests to servers. Which means if a request comes for the first time to the load balancer server, it will be routed to server A. If the page is reloaded and request is sent again then it will be routed to server B. The servers will be switched back and forth every time a request comes in. I’ve added an index in every servers and place some demo text in it to give you some indications about which server the request is currently hitting.

Creating a simple ASP.NET web application and deploying

Download the source code. The application contains two pages, one is the Index.aspx and another one is the Result.aspx. Below are the markup and the code behind for both of the pages,

Index.aspx markup:


<form id="form1" runat="server">
<div>
    <h1>Storing Session Data in Azure Redis Cache Server A</h1>
    <asp:TextBox ID="NameTextBox" runat="server"></asp:TextBox>
    <asp:Button ID="GreetButton" runat="server" Text="Greet!!!" OnClick="GreetButton_Click"/>
</div>
</form>

Index.aspx code behind:


protected void GreetButton_Click(object sender, EventArgs e)
{
    string name = NameTextBox.Text;
    Session.Add("MyName", name);
    Session.Add("SessionTime", DateTime.Now);
    Response.Redirect("~/Result.aspx");
}

Result.aspx markup:


<form id="form1" runat="server">
<div>
    Server A - 
    <asp:Label ID="NameLabel" runat="server" Text="Label"></asp:Label>
</div>
</form>

Result.aspx code behind:


protected void Page_Load(object sender, EventArgs e)
{
    object name = Session["MyName"];
    object time = Session["SessionTime"];
    if (name != null && time != null)
        NameLabel.Text = "Hi! " + (string)name + ", your last session state stroing time was: " + time; 
}

Change the string literal inside <h1> tag of Index.aspx and <div> tag to match your server names (Server A/ Server B/ Staging Server) when you deploy to have a better understanding which server you are currently on when testing the application. Deploy the application in all the servers using file system (run your Visual Studio as administrator if you got access denied error)

Browse to localhost:9000. Servers will be toggled back and forth every time a new request is sent but sessions will be different for each of the servers (server-a, server-b)

Downloading and running Redis (redis-server)

  • Install Redis x64 server from nuget or chocolatey. Here is the command to put in the package manager console of Visual Studio,
    Install-Package Redis-64

  • And here you can install it from chocolatey,
    https://chocolatey.org/packages/redis-64

  • After installation double click on redis-server.exe to run the Redis server
    • Run redis-cli from command prompt
    • Type ( keys * ) to get all the stored keys.

Testing session state with redis-cli

We are almost at the end; we need is a nuget package. The package is RedisSessionStateProvider. Here is the command to install it from package manager console,

Install-Package Microsoft.Web.RedisSessionStateProvider

To make Redis store our sessions, we need to add these lines to our web config file.

If this already exists, then all is good. Deploy the project again in your three servers and give it a spin, you will see all your session state is persisted successfully

As you can see I’m setting the text of the textbox in a session and passing it around. Later on, the value is shown in both of the Result.aspx pages of two servers i.e. our session is persisted. If you see the source code, you will see that I’ve used two session variables, one for input in the textbox and another for the current date and time. Both are saved as encrypted keys in the Redis store

Source Code

Download from here - http://1drv.ms/1ZFgfkR