Monday, August 4, 2014

Cookie based Caching of ASP.NET Page or Control

The Page Caching mechanism of ASP.NET is pretty straightforward and very simple to do.  Caching gives you performance gains in terms of rendering your HTML in response to a request.  This allows you to avoid hitting postbacks and sometimes roundtrips from your server-side code to SQL server perhaps.  Depending on your requirement, you may want to cache the whole page or just the control (ascx).  It only takes a small decision whether you want to cache or not.

In my projects, here are some criteria that I consider:
  1. Is your server's memory still capable of doing caching?  
  2. How big is the data to be cached?
  3. Does it always hit SQL-server in every postbacks or page loads?
  4. Does the data to be displayed are static in a certain period? maybe hours or days?

The OutputCache directive to the page or control will help you to implement the caching.  According to MSDN, this directive will give you the following options or parameters for caching.


DurationRequired. Time, in seconds, the page should be cached. Must be a positive integer.
LocationSpecifies where the output should be cached. If specified, must be one of: Any, Client, Downstream, None, Server or ServerAndClient.
VaryByParamRequired. The names of the variables in the Request, which should result in, separate cache entries. "none" can be used to specify no variation. "*" can be used to create new cache entries for every different set of variables. Separate variables with ";".
VaryByHeaderVaries cache entries based on variations in a specified header.
VaryByCustomAllows custom variations to be specified in the global.asax (for example, "Browser").


But I will focus only on how to cache using a cookie value.  And with that I will be discussing more on the VaryByCustom attribute.

Declaration

To declare caching mechanism simply place below code to your asp.net page (.aspx) or asp.net control (.asmx).  In this example, we will caching per CountryCode cookie.  This would mean that when CountryCode changes there is an equivalent cache data.

ASP.NET Page (.aspx)
<!-- directives -->
<% @Page Language="C#" %>                                <% @OutputCache Duration="3600" VaryByCustom="CountryCode" %> 


ASP.NET Control (.ascx)
<!-- directives -->
<% @Control Language="C#" %>                             <% @OutputCache Duration="3600" VaryByCustom="CountryCode" %> 
The duration in this case is 3600 means an hour of caching.  What is important here is the VaryByCustom feature.  This means that the caching mechanism is looking for that variable as its parameter and basis for caching.

Now inorder for this feature to work, we must have the following code in the Global.asax file to provide us application-wide VaryByCustom.

Global.asax
public override string GetVaryByCustomString(HttpContext context, string arg)
{
    if(arg == "CountryCode")
    {
        return this.CountryCode; // a property that will grab cookie
    }
    return base.GetVaryByCustomString(context, arg);
}
public string CountryCode 
{
    string currentLocation = "US"; 
    if (Cookies["CountryCode"] == null) {
           Cookies["CountryCode"] = currentLocation;
    }
  else {
          currentLocation = Cookies["CountryCode"];  
   }
       return currentLocation;
}

What is happening here is that in every request of page where OutputCache was declared, this method will always be executed and must return the value of VaryByCustom and in this case the CountryCode variable in which the value is from a cookie.

When ASP.NET runtime cache this, it will never hit any events of the Page Life Cycle not even the initialization events.  ASP.NET rather grabs the equivalent HTML from the server's memory.

Practical Usage
In this setup, you may want to cache banner images that is country specific.  You could probably grab the images or any other content from your SQL tables or other sources.

ASP.NET MVC
In ASP.NET MVC, the OutputCache directive is an attribute wherein you can apply it on either a Controller class or an Action in the controller class.  You can refer to the MSDN link.


No comments: