This post was originally published on Coding Glamour.

Dynamische pagina's, of het nou in PHP, CGI of .NET is, hebben het internet gemaakt tot wat het nu is; maar hebben één groot nadeel. Voor elk request dient de pagina opnieuw te worden gegenereerd. Oplossing: cachen. Nu hebben we hiervoor in ASP.NET MVC het 'OutputCache' attribuut, dat je op elke Action kan zetten:

// cache voor 1 minuut
[OutputCache(Duration = 60, VaryByParam = "id")]
public ActionResult Detail(int id) {
    // haal model op
    return View();
}


Probleem
Iedereen die deze pagina de komende minuut opvraagt krijgt dezelfde versie te zien. Geen probleem voor pagina's die more-or-less statisch zijn, maar funest wanneer je bijvoorbeeld login informatie toont! Voeg je bijvoorbeeld Output caching toe aan het standaard ASP.NET MVC 2 project (In VS 2010 -> New Project -> ASP.NET MVC 2 Web Application) dan krijg je de volgende situatie:
http://www.100procentjan.nl/tweakers/cache1.png
Overzichtspagina, je ziet de 'last update' datum ter referentie

http://www.100procentjan.nl/tweakers/cache2.png
Nu loggen we in

http://www.100procentjan.nl/tweakers/cache3.png
De pagina wordt uit cache geladen (zie 'last update') maar er staat nog steeds een 'Log on' knop ipv. 'Logged in as jan'. Oplossing?
De techniek om een hele pagina te cachen behalve een of meerdere kleine stukjes heet 'Output Cache Substitution' of 'Donut Caching', maar dit zou in MVC 2 en MVC 3 niet meer mogelijk zijn. Dat roept om een uitdaging!

Daarom...
Alvast een sneak preview van een project dat ik binnenkort hoop te open sourcen, dat Donut Caching toevoegd aan ASP.NET MVC.

Maak een nieuwe controller 'SharedController' aan in het standaard MVC project, met daarin de actie 'Datum'.

    public class SharedController : Controller
    {
        public ActionResult Datum()
        {
            return View();
        }
    }

In de view die hierbij hoort outputten we de huidige datum & tijd:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<%=DateTime.Now %>


We kunnen nu de datum tonen (en dus controleren of er gecachet wordt) door in de Shared/Site.master de regel toe te voegen:

<p>Last update <% Html.RenderAction("Datum", "Shared"); %></p>

Elke keer dat je de pagina nu refresht zie je dat de datum verandert.

Caching aanzetten
Ook hier werken we weer met een attribuut dat je moet toevoegen aan je Action, met de naam (subject to change) 'ActionRenderOptimizer':

// In Controllers/HomeController.cs
 [ActionRenderOptimizer(OutputCaching = true)]
 public ActionResult Index()
 {
     ViewData["Message"] = "Welcome to ASP.NET MVC!";
     return View();
 }

Wanneer je nu de homepage opvraagt zie je dat de datum steeds hetzelfde blijft. Deze zit namelijk in cache.

Deel van de pagina niet cachen?
Wanneer je nu een deel van je pagina niet wil cachen, vervang je de 'Html.RenderAction' door 'Html.RenderDonutAction'. Om dit te verifieren vervang je de regel in je masterpage door:

<p>Last update: <% Html.RenderAction("Datum", "Shared"); %></p>
<p>Last update donut: <% Html.RenderDonutAction("Datum", "Shared"); %></p>

Roep je nu de pagina op, dan zie je dat een van de twee datums elke keer opnieuw wordt gegenereerd!

http://www.100procentjan.nl/tweakers/cache4.png
Eerste request

http://www.100procentjan.nl/tweakers/cache5.png
Tweede request

Binnenkort te downloaden
Binnenkort te vinden op CodePlex!