ASP.NET MVC3 Caching

ASP.NET MVC3 builds on the caching abilities found in previous versions of ASP.NET and adds partial page output caching to your toolbox. Partial page output caching allows you to cache the rendering of a specific action on your view to enable your site to run faster. This can be a great technique to avoid unnecessary database calls to reduce server load and decrease client latency.

Rendering a Partial View

Razor allows you to encapsulate portions of your page in partial views that are roughly analogous to the ASCX user controls in classic ASP.NET. Your partial view needs to define a controller action similar to the controller actions of your normal page actions with the key difference that you'll be returning a PartialViewResult object instead of a generic ActionResult.

There is one parameter in the code example below that we use to build a string including that parameter along with the current time. The controller returns the string using the PartialView helper method to generate the PartialViewResult object.

public PartialViewResult CachableAction(string SomeParameter)
{
string returnValue = String.Format("Parameter:{0}<br>Time:{1}", 
SomeParameter, 
DateTime.Now.Ticks.ToString());
return PartialView("CachableAction", returnValue);
}

Right click on the partial view name defined in your controller and choose "Add View". In the dialog that appears, check the box next to "Create as a partial view". The resulting cshtml file generated will be completely blank instead of including the normal pieces you'd see when creating a blank page.

The view in this example renders the string returned from the controller along with a message.

@model string
<p>This is from my CachableAction</p> 
@Html.Raw(Model)

You call your partial action in your main page by using the @Html.Action razor helper method. This method allows you to call your partial action and have it run inline on the page. You can use this method anywhere including layout pages and even inside of other partial views.

<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
        <p>This is the page.</p>
        @Html.Action("CachableAction", "Home", new { SomeParameter="Yes" })
        @Html.Action("CachableAction", "Home", new { SomeParameter="No" })
    </div>
</body>
</html>

Adding Caching to Your Partial View

You can add caching to any of your controller actions by adding the [OutputCache] attribute to your methods. The OutputCache has some implied functionality you need to be aware of. B If your controller action has any parameters, like the "SomeParameter" in this example, and if the value varies between calls, it will cache a separate result for each parameter.

You must always define the Duration parameter when you use the OutputCache attribute. Duration is the amount of time in seconds that the cached result is good for. Be sure to choose something reasonable based on your application's constraints. If, for example, you're caching a list of categories that will only change rarely, it's probably fine to set your duration to be several hours long. If it's something like a product information page that might change more frequently, you might set the caching duration to less than a minute.

Although the cache will automatically vary by the parameters defined on your controller action, you can override this behavior by setting the VaryByParam option. VaryByParam will cache your control based on the values defined in the HTTP GET parameters or the form fields defined in this list. You can specify multiple parameters by separating each one with a semicolon.

[OutputCache(Duration=60,VaryByParam="ParamA;ParamB;")]
public PartialViewResult CachableAction(string SomeParameter)
{
...
}

VaryByCustom

VaryByCustom allows you to define custom key/value options to vary your caching by. You can do this by overriding GetVaryByCustomString in your Global.asax.cs file. This function will be called any time VaryByCustom is called. ASP.NET's cache will look at the string returned by this function and if it matches a value already in its cache, that is the value it will use. In the example below, if custom has "Browser" as the VaryByCustom value and the user's browser is "AOL" then it will return the string "AOL" as the value.

public override string GetVaryByCustomString(HttpContext context,  string custom)
{
if(custom=="Browser")
{
If(context.Request.Browser.AOL) { return "AOL"; }
else { return "NotAOL"; }
}
return Guid.NewGuid().ToString();
}

Across your entire application, you only have one place to define your GetVaryByCustomString method so you need to be careful to insure there isn't any unintended caching where it isn't desired. One way to insure this is to return a GUID in string form if none of your custom strings was matched, so your view won't be cached if it isn't supposed to be cached.

To call your GetVaryByCustomString in your global.asax.cs file, add a VaryByCustom parameter to your controller's action method.

[OutputCache(Duration=60,VaryByCustom="Browser")]
public PartialViewResult CachableAction(string SomeParameter)
{
...
}

Restrictions on Partial View Caching Options

Not all of the options available on the OutputCache attribute are valid to use on partial actions. Page-wide types such as Location, VaryByHeader, NoStore, SqlDependency, CacheProfile and VaryByEncoding will result in errors if you attempt to use them.

Security

It is very important to keep in mind that the cache is shared among all of the users of your application. This means if your partial view renders data specific to User A, User B will see User A's data unless you have some specific mechanism in place to keep them separated such as the SessionID. In general, however, it's not very efficient to cache anything on a per-user basis. The amount of server resources consumed per-user could quickly get out of control. As a result of this consideration, it's highly recommended to only cache things that are not user specific.

Conclusion

ASP.NET MVC3's partial views are powerful and efficient ways to add additional modularity to your web application. Adding the ability to cache these views can result in a dramatic reduction in latency and server resources if used correctly.



Related Articles