I'm working on a new personal project during my free time and I chose to develop it with ASP.NET MVC 4 (hosted on Azure of course...) to test the new features of this version.
In this project, I need to display "Logged in as xxxx " (if the user is logged...) in the header of the page. This is a simple scenario to implement but caching could complicate the development of my web app...
My header is in my layout and is used everywhere but I would like to place an OutputCacheAttribute on some actions (the home page, etc.). If I put the attribute on an action, all of my users will see an header with "logged in as xxxx" of the first incoming query!
The solution to this problem is named "Donut Caching": you send a cached page from the server with a "fresh" portion which is not in cache (the donut's hole).
Concretely, the server does not generate the requested page (query the DB, etc.): it just needs to take the cached version and replace a specific part.
Luckily, you do not need to develop your own custom
OutputCacheAttribute because there is already a very good package (
There's An App A Pack For That... thanks NuGet!):
MvcDonutCaching for ASP.NET MVC 3 and later...
To install the package, you can search through NuGet or directly type the following command in the "Package Manager Console":
1: install-package MvcDonutCaching
The use of this package is very simple... They have created several extension methods for HtmlHelper with the usual parameters plus another boolean parameter: excludeFromParentCache. I just have to call my partial view (with the "connected has xxxx"...) like that:
1: ...
2:
3: @Html.Action("LoginHeader", "Account", new { lang }, true)
4:
5: ...
The last parameter of Html.Action is set to true: this partial view will be excluded from the parent cache (if there is a cache on the action...). (do not pay attention to new { lang }, it's a route's value)
To make it work, you must not use the OutputCacheAttribute but the DonutOutputCacheAttribute:
1: [DonutOutputCache(Duration = 60, VaryByParam = "lang")]
2: public ActionResult Index(string lang)
3: {
4: ...
5:
6: return View();
7: }
And that's it! The first request will be cached during 60 seconds but the LoginHeader partial view will be generated every time.
(note: of course, the donut caching only works on the server side...)