Here’s How To Make Sure You’re Not Returning Zombies From An MVC Action

So there I was, minding my own, returning a Thing from a Controller Action as JSON. Like you do.

public ActionResult GetCriticalUpToTheMomentSortOfData(int id)
{
    using (var db = new ThingiesContext())
    {
        var thing = db.Things.Find(id);
        return Json(thing, JsonRequestBehavior.AllowGet);
    }
}

 

zombies1

One of my very favorite slightly off-label uses for ASP.NET MVC has been[1] to use an Action method as a mini-web service, returning data rather than markup. But this day, it wasn’t my very favorite slightly off-label use. It wasn’t even my second favorite.

I was sure that the value in the database was getting updated (by my actual favorite code, not listed). I queried, and queried again, my over-caffeinated eyeballs riveted to the results grid in SQL Server Management Studio. But, says my $.ajax() success callback, he says, the call is still returning the old value. The method was very straightforward about getting that value afresh from the database and returning it, and so I began to question the most basic of my nerdly assumptions. Do I have the right connection string? Should I even be using SQL anymore? Is the fabric of the universe collapsing?

After a therapeutic session of pacing and taking in some Carl Sagan to re-staple my faith in the sturdiness of the cosmos, it dawned on me that this particular service call was in fact an HTTP request made from a browser. And yes, the damned thing was caching.

Here’s What I Did After I Was Finished Shaking My Fists At The Sky During A Torrential Downpour

To remedy any further zombie data tomfoolery, I have here a NoCacheAttribute class that inherits from ActionFilterAttribute:

public class NoCacheAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var cache = filterContext.HttpContext.Response.Cache;
        cache.SetExpires(DateTime.UtcNow.AddDays(-1));
        cache.SetValidUntilExpires(false);
        cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        cache.SetCacheability(HttpCacheability.NoCache);
        cache.SetNoStore();

        base.OnResultExecuting(filterContext);
    }
}

This meek mod merely intercepts the result, grabs ahold of the HttpResponse‘s cache settings and beats them soundly about the head and shoulders until they are certain that they’re not going to cache anything that comes from this response. Like, ever.

And here’s me using it in an demonstrable sort of way with my code from before:

[NoCache]
public ActionResult GetCriticalUpToTheMomentSortOfData(int id)
{
    using (var db = new ThingiesDataContext())
    {
        var thing = db.Things.Find(id);
        return Json(thing, JsonRequestBehavior.AllowGet);
    }
}

Now I can sleep again, lullabied into rapid eye movement by the knowledge that this call is always returning the most up-to-the-moment-as-possible values, as advertised. And that another zombie apocalypse has been narrowly averted.


  1. “Has Been”, because it’s worth noting that this off-label silliness is about to not even be a thing anymore—ASP.NET 4.5’s Web API places this sort of action squarely on-label, and renders the whole Night Of The Living Data thing irrelevant for anyone who isn’t maintaining the last few year’s worth of terribly clever MVC code.That is not to mention that the first step to that sort of gig would be to upgrade to a proper Web API.Anyway.
Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s