Of Code and Me

Somewhere to write down all the stuff I'm going to forget and then need

Donut caching in asp.net mvc 2 with Html.Action April 8, 2010

Filed under: Asp.Net,C#,MVC,Uncategorized,Web — Rupert Bates @ 11:22 am

[Update – ok, so this officially doesn’t work, which sucks. I’m having a look at alternatives, but at the moment it looks like that is going to be reverting to MVC 1.0]

To do donut caching in Asp.Net Mvc 1.0 required quite a bit of hacking (or at least that was the only way I could get it to work), but with version 2 things get much better because of the addition of the Html.Action method.

As a quick recap, ‘donut caching’ is when you cache the whole of a web page except for small parts within it – the holes in the donut. A classic use for it is pages which have some personalised aspect like a logged in user name but are otherwise identical for all users.

To solve exactly this scenario I used the following code:

A child action called LoggedInUserInfo in my HomeController

        public ActionResult LoggedInUserInfo(HttpContextBase context)
            return View(context);

with a view of the same name:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<HttpContextBase>" %>
<%@ Import Namespace="KableDirect.Service" %>
<%@ Import Namespace="KableDirect.Web.FrontEnd.Models.Shared"%>

        <li>You are logged in as <%= Model.User.Identity.Name %> </li>

        <li><%=Html.ActionLink("My Profile", "Profile", "Account")%></li>

        <%if (Model.User.IsAdmin()){%>
        <li><a href="<%= RouteHelper.GetAdminUrl(Model)%>">Admin</a></li>
        <li><%=Html.ActionLink("Logout", "Logoff", "Account")%></li>

I also have the following HtmlHelper method to make calling the asp.net WriteSubstitution() method easier:

    public delegate string MvcCacheCallback(HttpContextBase context);
    public static class CacheHelper
        public static object Substitute(this HtmlHelper html, MvcCacheCallback cb)
            html.ViewContext.HttpContext.Response.WriteSubstitution(c => cb(new HttpContextWrapper(c)));
            return null;

Now I can call my child action within my MasterPage using Html.Action as follows:

<%=  Html.Substitute(context => Html.Action("LoggedInUserInfo", "Home", new {context}).ToString()) %>

It is important that your action takes the context as a parameter or it will only be called once the first time the page is hit and then get cached along with everything else.
It is also important that you have a route in your route table that will catch the {controller}/{action} url pattern. See this post for more details.

Phill Haack now has a warning on his site about problems with donut caching in Asp.Net Mvc 2, but this has worked fine for me, I’ll update here if I find scenarios where this doesn’t work.

There is a good introduction to Html.Action here.


2 Responses to “Donut caching in asp.net mvc 2 with Html.Action”

  1. JanJ Says:

    Donut caching is available for ASP.NET MVC 2 and 3 in ‘Moth’ (NuGet: Install-Package Moth). See the docs at the Github wiki.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s