Zip Compressing ASP.NET Session without changing your code using a Session provider.

Scott Hanselman had a post last week to zip your Session state. a great idea I thought to be able to save memory on the computer. Yet I didn’t want to change all my source code to use another class to do so, a nightmare to track all the Sessions in every application, or worse when you don’t have access to that source code.

So last weekend I work on a Session State Provider that allows me to intercept every call to the Session State and compressed when set or unzip when retrieve.

The Session State provider will call my method by adding this to the web.config on your website:

<sessionState cookieless="true" regenerateExpiredSessionId="true" mode="Custom" customProvider="ZipSessionProvider">
    <providers>
       <add name="ZipSessionProvider" type="ZipSession.ZipSessionProvider"/>
    </providers>
</sessionState>

This tells the web application to send all Session request to my class ZipSessionProvider that wraps Scott Hanselman’s class. There are 2 methods that are important on the provider, to set the session and to retrieve. So users don’t have to change the code to use the Sessions on their web applications:

Session["Something"] = "Hello World";

Insert a Session object.

public override void SetAndReleaseItemExclusive
            (HttpContext context, String id, SessionStateStoreData item,
            object lockId, bool newItem)
        {
            for (int i = 0; i < item.Items.Count; i++)
            {
                string sKey = item.Items.Keys[i];
                Zip.Session[id + sKey] = item.Items[i];
            }
        }

The system calls the SetAndReleaseItemExclusive to set Session variables. As when you override the Session state, you’ll find you won’t get a Session initialize for you. That’s ok or better, as we’ll use the Cache object to store our session state, more control over that. The method above will store the sessionID as well with the Key for easy retrieve later on.

Retrieve a session object.

public override SessionStateStoreData GetItemExclusive
           (HttpContext context, String id, out bool locked,
           out TimeSpan lockAge, out object lockId,
           out SessionStateActions actions)
       {
           actions = SessionStateActions.None;
           lockId = null;
           lockAge = TimeSpan.MaxValue;
           locked = true;
           SessionStateStoreData temp = new SessionStateStoreData(
                   new SessionStateItemCollection(),
                   SessionStateUtility.GetSessionStaticObjects(context),
                   20
               );

           for (int i = 0; i < Zip.SessionItems.Count; i++)
           {
               if (Zip.SessionItems[i].ToString().Contains(id))
               {
                   string sKey = Zip.SessionItems[i].ToString().Replace(id, "");
                   temp.Items[sKey] = Zip.Session[Zip.SessionItems[i].ToString()];
               }
           }
           return temp;
       }

Even if we call the SessionStateStoreData we need to provide all the objects and the correct name as well as filtered by Session id.

Modification on Scott’s code.

I had to make 2 modification on Scott’s code, not to fix errors, just to adjusted to my needs.

public class ZipCacheInternal  
       {  
           public object this[string index]  
           {  
               get  
               {  
                   return GZipHelpers.DeCompress(HttpContext.Current.Cache[index] as byte[]);  
               }  
               set  
               {
                   HttpContext.Current.Cache[index] = GZipHelpers.Compress((string)value);
                   SessionItems.Add(index);
               }  
           }  
       }  

Instead of be a string indexer I changed it to be able to store any kind of object as well as I keep track of all session on an Array.

Testing the code.

Now we can run the code to test the application, a simple web form with 2 buttons, one to set and the other one to retrieve the session previously set.

protected void Page_Load(object sender, EventArgs e)
    {
        if (Page.IsPostBack == false)
        {
            Session["Something"] = "Hello World";

            Response.Write("Test");

            Label1.Text = "";
        }
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = Session["Something"].ToString();
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        Session["Something"] = TextBox1.Text;
    }

image

Of course I provide you with all the source code and the test application for you to improve my code. There are still a few things I would like to add as well a few things that I didn’t implement in the provider. So expect a few bugs and issues.

Download it from here

Summary

This is the first cut to see how it behaves, I’ll be adding some of the functionality that Scott was talking on his great post. For once, check if compression that object will reduce the bytes, some objects are bigger when compressed.

Hope this helps

Cheers

Al

7 Comments

  • Compressing short strings is wasteful. I'd have thought you'd want to limit the use of compression to the cases (e.g. long strings) where it will make a difference. Therefore would want an API that allows the caller to choose whether or not to compress. Therefore would not simply replace the session state provider in this way.

  • On a server that is loaded to any level this would actually help, the Cache will be regularly pruning objects so there is a VERY high percentage chance that the objects you put into the Cache object won't come back out (they'll be null). You need to A) have a secondary store for them and B) be more defensive about the access to Cache; check for null and punt back to secondary store.

  • If short strings is a concern, you could always all logic to the ZipSessionProvider to only compress strings with length < some value.

  • nice statements ive learned a lot.

  • Hi, the link for downloading the sourcode does not work.

  • Hi, the link for downloading the sourcode does not work.

  • Wow! I could not even guess about it)) Not bad.

Comments have been disabled for this content.