Saturday, 20 August 2011

Implementing Session State Management in Azure Roles - Part1


As we already know, HTTP is a stateless protocol. So, once an ASP.NET page created on the server and sent the response to client, server will not retain any values which were used for processing the page. In that case, if any user log-in to a system with some important values such as User Id, Role, Branch etc., and those values are required while generating further pages. So, those values must be retained till the end of the session.

ASP.NET provides various ways for holding the states between requests; they are categorized in two types
  1. Client-side State Management - View State, Control State, Hidden fields, Cookies, Query String
  2. Server-Side State Management – Application State, Session State, Profile Properties, Database

ASP.NET Session object enables the ASP.NET application to hold important values on the server which are specific to a particular session. The life time of the session will be till the browser closed or the session time expired.

How Session works in Azure

In Azure roles also we can use the Session object as like the same way we use in ASP.NET applications. But here the sessions need to be an out-proc state.

Normally, ASP.NET applications will be hosted on a Web Server and the entire request will be go thro’ a single IIS server. Once the session variable created using Session object, it will be managed by the server. Any request come to the same server from that specific session, it will use the same session by identifying with Session ID.

In Azure roles, we may have multiple instance (means multiple server). So it is not guaranteed that, all requests from the same browser will go to a single instance. The load balancer is responsible to route the request to any web role instance. It may route to Instance 1 for the first request and instance 2 to next request. As each role instance has its own session and those won’t be shared among other roles, in first request if we store some of session values to the Session object (which may store in Instance 1), the next request (which may route to Instance 2) may not get the same values (will be null) because the same session won’t be available in different instance. This will be a critical issue when we host the Web Role with multiple instances.

Below figure shows how the request comes from the user to load balancer and routed to different Web Roles.


Here, a Web Role hosted with two instances (Instance 1, Instance 2). Whenever a request rose, it will first go to load balancer. The load balancer takes the responsible to route the request to a particular Instance and it will be done in rotate fashion. So, if first request goes to Instance1, the next request goes to Instance 2. The next request again will start from Instance 1. It will complete a cycle of Instances and start from first.

In this figure, the first request goes to load balancer and route to Instance 1. The first request authenticates the user and store the session in to Session object. So Instance 1 will have Session of the User 1. When the next request goes to load balancer, it will route to Instance 2 (incase if there is no other request come to it in between from any other user). The second request will get the session from Session object and process some reports. But here no session exist because it is Instance 2. The third request will work fine if it route to Instance 1. This issue will be more if more requests come from different users.

But, this issue will not happen in case if there is only one instance is running for a role as the entire request goes to the same Instance (IIS). But real time enterprise application required more than one instance for high availability, scalability.

How to solve this issue?

So, doing this way will not work in Azure Roles with multiple instances. How to solve this issue?

If you remember in some enterprise applications, there will be multiple web servers running for different modules and use same session. In that situation, we will be having any of out-proc session such as State Server or SQL Server and store the session into a different server (let’s call it as session server) and use it in all modules pointing to the session server.

We are going to use the same model, but we are going to store the session details in Azure Table Storage service. So, when user logs in to the application the session will be serialized and stored the details into Table Service and the same will be de-serialized when the session gets back. The coding will be same as the normal ASP.NET application code, but with some settings.

Understanding the Session issue with a POC

Let us understand the concept using a POC and modify the same project for handling Sessions by storing it into Table Service.

Step 1: Create a sample Azure Web Role Project. I name the project as SessionPOC and role as WebRole.
Step 2: Create a Web page in the Web Role and name it as Welcome.aspx. This page is used for getting some values for storing into session such as User Name, User Role. Make this page as Start Page.
Step 3: Add the following UI script for getting User Name, User Role values in the aspx script.
<asp:Label runat="server" ID="lblRoleId" Text=""></asp:Label>
<br />
User Name : <asp:TextBox ID="txtUserId" runat="server" Text=""></asp:TextBox>
<br />
User Role : <asp:TextBox ID="txtUserRole" runat="server" Text=""></asp:TextBox>
<br />
<asp:Button ID="btnSubmit" runat="server" Text="Login" onclick="btnSubmit_Click" />
Step 4: Add a btnSubmit_Click event in the code behind with code for storing these values into Session. Once the session values are stored into Session, the page redirects to Default.aspx. On Page load, the Role Id will be assigned to label to show..
protected void Page_Load(object sender, EventArgs e)
{
    lblRoleId.Text = "Role Instance : " + RoleEnvironment.CurrentRoleInstance.Id;
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
    Session["UserId"] = txtUserId.Text;
    Session["UserRole"] = txtUserRole.Text;

    Response.Redirect("Default.aspx");
}
Step 5: Add a label control in Default.aspx page. This control is used to show the session details.
<asp:Label runat="server" ID="lblSessionDetails" Text=""></asp:Label>
Step 6: Add the following code in Page_Load event of Default.aspx page. This code is getting the session details and assigning the values to label just added in the script.
string sessionId = Session["UserId"] != null ? Session["UserId"].ToString() : string.Empty;
string roleId = Session["UserRole"] != null ? Session["UserRole"].ToString() : string.Empty;

lblSessionDetails.Text = "Role Instance : " + RoleEnvironment.CurrentRoleInstance.Id + 
                            " User Id : " + sessionId + 
                            " Role : " + roleId;
Note: Add Microsoft.WindowsAzure.ServiceRuntime assembly reference in the page.
Step 7: As in Default.aspx page, add a label control in About.aspx page.
<asp:Label runat="server" ID="lblSessionDetails" Text=""></asp:Label>
Step 8: Add the same code added in Default.aspxPage_Load event in About.aspx page also.
string sessionId = Session["UserId"] != null ? Session["UserId"].ToString() : string.Empty;
string roleId = Session["UserRole"] != null ? Session["UserRole"].ToString() : string.Empty;

lblSessionDetails.Text = "Role Instance : " + RoleEnvironment.CurrentRoleInstance.Id + 
                            " User Id : " + sessionId + 
                            " Role : " + roleId;
So here, we have two pages Default.aspx, About.aspx page to show the session details we assigned in Welcome.aspx page.

Let’s test the application and see the output.

Testing with 1 instance.
  1. In the solution explorer, expand the Roles node under Azure project (SessionPOC).
  2. Double click the WebRole or right click the WebRole and select the properties.
  3. Under the Configuration tab, confirm the Instance count value is set to 1.
  4. Run the application. It will show Welcome.aspx page.
  5. Give User Name and Role and press Login. It will redirect to Default.aspx page.
  6. When Default.aspx page shows it will show the session details which given the input in Welcome.aspx page.
  7. In the Navigation Menu, press About. It will show About.aspx page.
  8. The About.aspx page also shows correctly with stored session details.
  9. If I switch the pages using the Menu Home and About, the session details shows perfectly what I stored in Welcome.aspx page.

Testing with 2 instance
  1. Change the Instance count to 2 for the Web role as done before and run the project.
  2. In the Welcome.aspx page, enter the User Name, Role and press Login.
    Note: the Role Instance will be deployment(xxx).SessionPOC.WebRole.0
  3. The browser will show Default.aspx with the following details.
    Role Instance : deployment(xxx).SessionPOC.WebRole.0
    User Id :
    Role :
  4. Click the Home and About menus and verify the Role Instance, User Id and Role details. The browser will show session details correctly in alternative page show.

Why it is happening?

When Welcome.aspx shows, the Role Instance Id is deployment(xxx).SessionPOC.WebRole.0

When pressing Login button, the page gets Post back. It goes to the server, the load balancer will redirect to instance Id 1. So the session gets stored in Instance Id 1.

Once it redirects to Default.aspx, there is a round-trip. So request goes with Instance Id 0. But session stored in Instance 1.

So whenever the page generated with Instance Id 1, it gets the session correctly and show to the user.

How to Solve?

Please verify the Implementing Session State Management in Azure Roles - Part2 post for the solution example


0 Responses to “Implementing Session State Management in Azure Roles - Part1”

Post a Comment