ASP.Net MVC Framework Server-Side HTML Caching Techniques

The ASP.NET Framework provides many out-of-the-box techniques to cache data on the server useful for improving system performance and reducing the load on the content providing servers.

The ASP.NET Framework provides many out-of-the-box techniques to cache data on the server useful for improving system performance and reducing the load on the content providing servers.

ASP.NET not only provides server-side data caching techniques, but also provides client-side rendered content caching, called Output Caching. This helps to cache the rendered HTML on the client side. Caching allows subsequent requests for the same page to be satisfied from cache itself.

ASP.NET provides the ability to cache at various levels like cache the page at the browser that is making the request at the Web server responding to the request and at any other cache-capable devices, such as proxy servers, that are in the request or response stream.

ASP.NET provides the ability to cache either an entire page or parts of the page, called fragment caching. We also have the many techniques described here.

1. Cache Versions of a Page Using Requesting Browser

Sometimes web applications contain a page that creates various output based on the type of the requesting browser, caching this page's output by the major version of the browser that requests the page also possible with ASP.NET.

Declaratively

<%@ OutputCache Duration="10" VaryByParam="None" VaryByCustom="browser" %>

Programmatically

protected void Page_Load(object sender, EventArgs e)

{

    Response.Cache.SetExpires(DateTime.Now.AddMinutes(1d));

    Response.Cache.SetCacheability(HttpCacheability.Public);

    Response.Cache.SetValidUntilExpires(true);

    Response.Cache.SetVaryByCustom("browser");

}


2. Cache Versions of a Page Using Parameters

In modern web development, most pages are dynamic; the same page may render various content based on the query string parameters. Caching these pages will also help to increase the site performance.

Let us say we have an air ticket booking site that retrieves the codes of all the airports based in the country, or sometimes even a country and state. Caching these pages will always boost the performance of the application.

Declaratively
 

<%@ OutputCache="" Duration="60" VaryByParam="Country" %>

<%@ OutputCache="" Duration="60" VaryByParam="Country;State" %>

Programmatically
 

Response.Cache.SetExpires(DateTime.Now.AddMinutes(1.0));

Response.Cache.SetCacheability(HttpCacheability.Public);

Response.Cache.SetValidUntilExpires(true);

Response.Cache.VaryByParams["Country"] = true;
 

Or
 

Response.Cache.SetExpires(DateTime.Now.AddMinutes(1.0));

Response.Cache.SetCacheability(HttpCacheability.Public);

Response.Cache.SetValidUntilExpires(true);

Response.Cache.VaryByParams["Country"] = true;

Response.Cache.VaryByParams["State"] = true;

3. Cache Versions of a Page Using HTTP Headers

ASP.NET allows you to cache multiple versions of a page depending on the value of an HTTP header; either single header, multiple or for all hears also possible to cache.

Declaratively

<%@ OutputCache Duration="60" VaryByParam="None" VaryByHeader="Accept-Language" %>

Programmatically
   

Response.Cache.SetExpires(DateTime.Now.AddMinutes(1d));

Response.Cache.SetCacheability(HttpCacheability.Public);

Response.Cache.SetValidUntilExpires(true);

Response.Cache.VaryByHeaders["Accept-Language"] = true;


For all headers

Response.Cache.SetExpires(DateTime.Now.AddMinutes(1d));

Response.Cache.SetCacheability(HttpCacheability.Public);

Response.Cache.SetValidUntilExpires(true);

Response.Cache.VaryByHeaders["VaryByUnspecifiedParameters"] = true;

4. Cache Versions of a Page Using Custom Strings

ASP.NET also supports output caching based on various strings returned by a method that you define in the code. When cached pages are based on custom strings, first specify an identifier for the custom string to use. Then create a method in the application's Global.asax file that accepts the identifier and returns a value to vary the output cache by. In the application's Global.asax file, override the GetVaryByCustomString method to specify the behavior of the output cache for the custom string.

Declaratively

<%@ OutputCache Duration="10" VaryByParam="None" VaryByCustom="minorversion" %>

Programmatically
 

public override string GetVaryByCustomString(HttpContext context, string arg)

{

    if(arg == "minorversion")

    {

        return "Version=" +

            context.Request.Browser.MinorVersion.ToString();

    }

    return base.GetVaryByCustomString(context, arg);

}

5. Validate the paged cache

When a request comes for a cached page, ASP.NET determines whether the cached output is still valid based on the cache policy defined in the page. If the output is valid then the cached output is sent to the client. However, ASP.NET provides the ability to run validation code during this validation check using a validation callback, to check whether the page is still valid.
 
The following handler named "isCacheValid" determines whether the query string variable status contains the values "invalid" or "ignore". If the status value is "invalid" then the method returns Invalid and the page is invalidated in the cache. If the status value is "ignore" then the method returns "IgnoreThisRequest" and the page is left in the cache but a new response is generated for this request.

public static void isCacheValid (HttpContext context, Object data, ref HttpValidationStatus status)

{

    if (context.Request.QueryString["Status"] != null)

    {

        string pageStatus = context.Request.QueryString["Status"];

 

        if (pageStatus == "invalid")

            status = HttpValidationStatus.Invalid;

        else if (pageStatus == "ignore")

            status = HttpValidationStatus.IgnoreThisRequest;

        else

            status = HttpValidationStatus.Valid;

    }

    else

        status = HttpValidationStatus.Valid;

}

The following defines an event handler of type "HttpCacheValidateHandler" in the page event life cycle and includes code that checks the validity of the cached page response.

protected void Page_Load(object sender, EventArgs e)

{

   Response.Cache.AddValidationCallback(

   new HttpCacheValidateHandler(isCacheValid), null);

}
 
6. Cache Page Output with File, Key/Item, SQL Dependencies

Sometimes ASP.NET gets data from a XML file or another key/item, some table updates. If something gets changed on these dependencies then we should invalidate the already cached data of these inputs.
 

protected void Page_Load(object sender, EventArgs e)

{

    string fileDependencyPath = Server.MapPath("biztalkOutPut.xml");

    Response.AddFileDependency(fileDependencyPath);

 

    // Set additional properties to enable caching.

    Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));

    Response.Cache.SetCacheability(HttpCacheability.Public);

    Response.Cache.SetValidUntilExpires(true);

}

You cannot use these methods from an ASP.NET user control. However, in any user control that specifies the '@OutputCache' directive you can create a file dependency and assign it to the "Dependency" property. You can also have multiple file dependencies to invalidate the cache.

 

protected void Page_Load(object sender, EventArgs e)

{

    string[] fileDependencies;

    string fileDependency1 = Server.MapPath("MyFile.txt");

    string fileDependency2 = Server.MapPath("biztalkOutPut.xml");

    fileDependencies = new String[] { fileDependency1, fileDependency2 };

    Response.AddFileDependencies(fileDependencies);

}
 
Key/Item Dependency
 

protected void Page_Load(object sender, EventArgs e)

{

    Response.AddCacheItemDependency("anotheritem");

    Response.Cache.SetExpires(DateTime.Now.AddSeconds(10));

    Response.Cache.SetCacheability(HttpCacheability.Public);

    Response.Cache.SetValidUntilExpires(true);

}
 
SQL Dependency
 

protected void Page_Load(object sender, EventArgs e)

{

    SqlDependency.Start(<Connection string>);

 

    using (SqlConnection connection =

        new SqlConnection((<Connection string>)

    {

        using (SqlCommand command =

            new SqlCommand(<SQL Statement>, connection))

        {

            SqlCacheDependency dependency =

                new SqlCacheDependency(command);

 

            int numberOfMinutes = 3;

            DateTime expires =

                DateTime.Now.AddMinutes(numberOfMinutes);

 

            Response.Cache.SetExpires(expires);

            Response.Cache.SetCacheability(HttpCacheability.Public);

            Response.Cache.SetValidUntilExpires(true);

 

            Response.AddCacheDependency(dependency);

 

            connection.Open();

 

            GridView1.DataSource = command.ExecuteReader();

            GridView1.DataBind();

        }

    }

}
 
7. Output Caching and ASP.NET MVC

With the introduction of MVC controllers in ASP.NET the caching framework has been extended to support the content caching at the controller level. Because each ActionResult in the controller creates a view and caching that view will make the application performance increase.

The ASP.NET MVC Framework provides the OutputCacheAttribute attribute to an action filter that tells ASP.NET MVC to add the rendered results of the controller action to the output cache. This attribute has the same number of parameters that we have seen to provide support of caching at the controller level.

  1. CacheProfile: The name of the output cache policy to use. This allows defining a global location to define all the caching policies for the OutputCacheAttribute, instead of defining for each ActionResult in the controller. It is in the Web.Config.
     

    <caching>

       <outputCacheSettings>

          <outputCacheProfiles>

          <addname="GetDetails"duration="3600"varyByParam="id"/>

          <addname="CachedDateTime"duration="60"varyByParam="none"/>                      

       </outputCacheProfiles>

     </outputCacheSettings>

    </caching>

     

  2. Duration: The amount of time in seconds to cache the content. The default is 60 seconds.
     

    [OutputCache(Duration=60, VaryByParam="none")]

    public ActionResult CachedDateTime()

    {

       ViewBag.Message = DateTime.Now.ToString();

       return View();

    }
     

  3. Enabled: Enables/disables the output cache for the current content.
  4. Location: The location of where to cache the content. The default is "Any". The other possible values are "Client", "Down stream", "Server", "None", or "ServerAndClient".
     

    [OutputCache(Duration = 3600, VaryByParam = "none", Location =OutputCacheLocation.Client, NoStore =true)]

    public ActionResult LoginUser()

    {

       ViewBag.Message = "The current user name is " + User.Identity.Name;

       return View();

    }
     

  5. NoStore: Enables/disables HTTP Cache-Control
     
  6. SqlDependency: The database and table name pairs that the cache entry depends on.
  7. VaryByContentEncoding:  A comma-delimited list of character sets (content encodings) that the output cache uses to vary the cache entries.
  8. VaryByCustom: A list of custom strings that the output cache uses to vary the cache entries.
  9. VaryByHeader: A comma-delimited list of HTTP header names used to vary the cache entries.
  10. VaryByParam: A semicolon-delimited list of form POST or query string parameters that the output cache uses to vary the cache entry. The most useful one in this list. Allow caching multiple versions of the view with different content.
     

    [OutputCache(Duration = 600, VaryByParam = "id")]

    public ActionResult GetDetails(string id)

    {

        var auction = _productDetails.Find<Auction>(id);

        return View("ProductDetails", auction);

    }