-->

26/09/2011

Session Sharing


Scenario: In one of the projects, i got a situation where Half of the application is Migrated to MVC and other half is in Old 3 tier architecture.
Now, i have to host both the applications, and need to switch the context from one app to other with out intervening the user actions. We use to save all the user context and other information in sessions to maintain the state.
Bottom line is "I have to share the sessions between two different virtual directories in order to maintain the continuity of the application."


Resolution : After verifying couple of approaches, we found that Session can be shared by using a combination of  Custom Http Module  and SQL State management. We will see how to do that step by step.
Before going to Actual implementation, we need to see what are the tables used for SQL state management and their significance, thus we can understand how to make them work as we require.

Sql Server State Management: We know what are the different steps to do in order to configure SQL State management. Lets Open and see ASPState database. You will have 2 data tables.
             #1. ASPStateTempApplications - This used to create a unique Appid for each in-comming application request based on the unique application name/ application ID.
            #2. ASPStateTempSessions - This is used to create unique sessions for each user, correlated with each applicationid created in #1 table.


Logic: Now, from #1, you might have observed if you have 2 different applications, there will be 2 different application ids that will be created in table #1. So our duty is to restrict both the applications to create a single Appid, and this is acheived by using custom HTTP Module.



HTTP Module: When and Why?
This question can e answered by the below image. HTTP Modules comes immediately after request hitting IIS. So, we can control / Modify different application level settings as per our requirement.
 Our requirement here is to modify App name for both of the applications before request hits the processing.

Step 1: Create 2 simple web application , which were hosted in IIS. All i am gona do is to capture a Session in web application1 and see whether we are able to retrieve it in Web application 2.


Step 2: I created a http module with name SharedSessionModule. The significance of it will be setting up a common application name for both the application requests.
namespace SharedSessionModule
{
    public class SharedSessionModule : IHttpModule
    {
        #region IHttpModule Members              
        public void Init(HttpApplication context)
        {
            try
            {
                // Get the app name from config file...
                string appName = ConfigurationManager.AppSettings["ApplicationName"];

                if (!string.IsNullOrEmpty(appName))
                {
                    FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
                    HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);

                    FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic);

                    appNameInfo.SetValue(theRuntime, appName);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }       
        public void Dispose()
        {
        }
        #endregion
    }
}

Step 3: Refer this module in both of the web applications.
               #. For this either you can refer a DLL, of you can dump the module file itself in the web app.
              #. Have the module configured by specifying it in modules section of your config file.
Code:
namespace SharedSessionModule
{
    public class SharedSessionModule : IHttpModule
    {
        #region IHttpModule Members              
        public void Init(HttpApplication context)
        {
            try
            {
                // Get the app name from config file...
                string appName = ConfigurationManager.AppSettings["ApplicationName"];

                if (!string.IsNullOrEmpty(appName))
                {
                    FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
                    HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);

                    FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic);

                    appNameInfo.SetValue(theRuntime, appName);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }       
        public void Dispose()
        {
        }
        #endregion
    }
}
Config:
<appSettings>
<add key="ApplicationName" value="CommonAppName"/>
</appSettings>
<httpModules>
 <add name="SharedSessionModule" type="SharedSessionModule.SharedSessionModule, SharedSessionModule"/>
</httpModules>

 Step 4: Verification.
First, Run web application 1 and capture a session.
The value is saved to session. Now navigate to webapp2 using the url below the message.
Now, you can see the session value is retried successfully in web app 2.


Lets try doing the same from web app 2.
Navigate to web app 1, and the session value captured in web app 2 was retrieved successfully.
Now, lets see how these session values are shared seamlessly between two web applications, the data in ASPState database tables can answer this question.
Now, you can see , all these operations are executed under one session and one application (CommonAppName). So, even when one user  switched between different applications, because of our custom Http Module, SQL server will treat them as one application (CommonAppName) and will provide a persistent session management for the user.

Is it helpful for you? Kindly let me know your comments / Questions.

No comments:

Post a Comment