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.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read