ASP.Net MVC Framework Donut & Donut Hole Caching

1. Donut Caching

Donut caching is a server-side caching technique in which the entire page is cached, except for small portions that remain dynamic.

OutputCache with VaryByParam serves most of the purpose for the web applications, but there are cases when it is necessary to cache an entire page while leaving dynamic sections not cached, like logged-in user name and local time display. In the ASP.NET MVC Framework the Razor View engine was the most successful framework, however even this does not have full support for this requirement. ASP.NET Web Forms offers the Substitution control to shape out the "holes" or dynamic sections out of the entire page.


  1. <header>  
  2.    <h1>Donut Caching Example 1</h1>  
  3.      <div class="UserName">  
  4.        <asp:Substitution runat="server" MethodName="GetUserName" />  
  5.      </div>  
  6. </header>

The Substitution control registers a callback event within the ASP.NET output cache and invokes a static method on the page when the cached page is requested.


  1. partial class DonutCachingPage : System.Web.UI.MasterPage  
  2. {  
  3.   public static string GetUserName(HttpContext Context)  
  4.   {  
  5.     return "Hello " + Context.User.Identity.Name;  
  6.   }  
  7. }

When the request comes for DonutCachingPage, the entire cached page is returned except for the username section, which continues to get generated for each request.

We can also develop the same logic with custom code that actually does what the Substitution control does. The HttpResponse class has the WriteSubstitution() method; it is what the Substitution control uses behind the scenes. Develop the following code with an extension method.

  1. public delegate string CacheCallback(HttpContextBase context);  
  2. public static object Substitution(this HtmlHelper myHtml, CacheCallback cacheCallback)  
  3. {  
  4.    myHtml.ViewContext.HttpContext.Response.WriteSubstitution(  
  5.       c => HttpUtility.HtmlEncode(  
  6.            cacheCallback (new HttpContextWrapper(c))  
  8.       ));  
  9.    return null;  
  10. } 

Use the following code that will produce the same output.

  1. <header>  
  2.   <h1>MVC Donut Caching  example 2</h1>  
  3.     <div class="UserName">  
  4.        Hello @Html.Substitution(context => context.User.Identity.Name)  
  5.     </div>  
  6. </header>  

2. Donut Hole Caching

Donut hole caching is the inverse of donut caching. While the donut caching technique caches the entire page, by leaving out only a few small sections, donut hole caching caches only one or a few portions of the page. Unlike donut caching, ASP.NET MVC has great support for donut hole caching through the use of the ChildActionOnlyAttribute attribute.

  1. [ChildActionOnly]  
  2. [OutputCache(Duration=3600)]  
  3. public ActionResult ProductsChildAction()  
  4. {  
  5.     // Fetch Categories from the database and  
  6.     // pass it to the child view via its ViewBag  
  7.     ViewBag.Categories = Model.GetCategories();  
  8.     return View();  
  9. }   

The OutputCacheAttribute attribute caches the Products for an hour, whereas the rest will be dynamic when you call the ProductsChildAction method in the HTML page.

  1. <header>  
  2.   <h1>MVC Donut Hole Caching Example 1</h1>  
  3. </header>  
  4. <aside>  
  5.   <section id="products">  
  6.     @Html.Action("ProductsChildAction ")  
  7.   </section>  
  8. </aside> 

The results of this call are cached via the OutputCacheAttribute attribute. When the page is rendered the next time, the Products list is rendered from the cache while the rest of the page is generated from scratch.

3. Distributed Caching

In modern web deployment, web applications are deployed to multiple web servers with a load balancer. With the Server-side Caching enabled, if one request is served by one server then data is cached on that server, now with load balance configuration it is not guaranteed that the same request goes to the cached server. If that request goes to another server then again the same page will be cached and that is redundant.

What if we could generate the Cache and share it with another server or even with the other farms? If we can do that then we can improve the performance of the web application.

The technique of caching data on one application instance and sharing it with other instances is known as distributed caching, and it is the most detailed of all caching techniques.

Distributed caching is an extension of caching techniques by which data from a database or session file system or another application is stored in a central location that all instances of an application have access to.

There are many advantages with the distributed caching, including the following:
  1. Performance

    Large data can stored in the servers in-memory; that improves the read performance and the page load will faster.

  2. Scalability

    Allows the application to scale to higher demands and load easily.

  3. Redundancy

    Redundancy ensures that if one server fails then the entire application does not suffer. Instead, another failover server can pick up the request and serve it without any manual intervention. Failover and redundancy are essential features of many distributed caching solutions.

4. Distributed caching solutions

There are a number of distributed caching products available today, and although each of these products offer very different APIs and ways of working with the data they manage, the basic concepts of distributed caching remain the same. Microsoft provides a solution for distributed caching, the Velocity or Windows AppFabric.

Similar Articles