47

Is there a way to programmatically invalidate portions of the ASP.NET MVC output cache? What I would like to be able to do is, if a user posts data that changes what would be returned from a cached action, be able to invalidate that cached data.

Is this even possible?

Yuck
  • 49,664
  • 13
  • 105
  • 135
Matthew Belk
  • 1,904
  • 2
  • 20
  • 28
  • Duplicate of: http://stackoverflow.com/questions/1200616/abort-outputcache-duration-programatically-in-asp-net-mvc and http://stackoverflow.com/questions/1167890/how-to-programmatically-clear-outputcache-for-controller-action-method – Drew Noakes Mar 15 '11 at 20:07

2 Answers2

39

One way is to use the method :

HttpResponse.RemoveOutputCacheItem("/Home/About");

Another way is described here : http://aspalliance.com/668

I think you could implement the second method by using a method level attribute for every action that you want and just add to it the string representing the key. That's if I understood your question.

Edit: Yes the asp.net mvc OutputCache is just a wrapper .

If you're using varyByParam="none" then you just invalidate "/Statistics" - that's if <id1>/<id2> are querystring values. This will invalidate all versions of the page.

I did a quick test and if you add varyByParam="id1" and then create multiple versions of the page - if you say invalidate invalidate "/Statistics/id1" it will invalidate just that version. But you should do further tests.

Snake Eyes
  • 16,287
  • 34
  • 113
  • 221
sirrocco
  • 7,975
  • 4
  • 59
  • 81
  • 1
    is the MVC OutputCache attribute just a wrapper around the usual ASP.NET output caching? So, let's say I wanted to invalidate the results for an action called "/Statistics//" I would just call HttpResponse.RemoveOutputCacheItem("/Statistics//")? FWIW, The "VaryByParams" property of the attribute is "None." Am I using that property correctly? – Matthew Belk Aug 17 '09 at 21:19
  • @Matthew Belk: Did you use this technique in the end? Did invalidation of a cache item by param work as expected? thanks. – UpTheCreek Jan 22 '11 at 10:20
  • I would recommend using MvcDonutCaching, more info available here http://www.devtrends.co.uk/blog/donut-output-caching-in-asp.net-mvc-3 – Pierluc SS Aug 02 '12 at 19:09
  • Link to ASP Alliance is broken – cbp Mar 26 '20 at 06:23
1

I did some test on caching. This is what I found:

You have to clear the cache for every route that lead to your action. If you have 3 routes that lead to the exact same action in your controller, you will have one cache for each route.

Let's say, I have this route config:

routes.MapRoute(
                name: "config1",
                url: "c/{id}",
                defaults: new { controller = "myController", action = "myAction", id = UrlParameter.Optional }
                );

            routes.MapRoute(
                name: "Defaultuser",
                url: "u/{user}/{controller}/{action}/{id}",
                defaults: new { controller = "Accueil", action = "Index", user = 0, id = UrlParameter.Optional }
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Accueil", action = "Index", id = UrlParameter.Optional }
            );

Then, these 3 routes lead to myAction in myController with the param myParam:

  1. http://example.com/c/myParam
  2. http://example.com/myController/myAction/myParam
  3. http://example.com/u/0/myController/myAction/myParam

If my action is as follow

public class SiteController : ControllerCommon
    {

        [OutputCache(Duration = 86400, VaryByParam = "id")]
        public ActionResult Cabinet(string id)
        {
             return View();
}
}

I will have one cache for each route (in this case 3). Therefore, I will have to invalidate every route.

Like this

private void InvalidateCache(string id)
        {
            var urlToRemove = Url.Action("myAction", "myController", new { id});
            //this will always clear the cache as the route config will create the path
            Response.RemoveOutputCacheItem(urlToRemove);
            Response.RemoveOutputCacheItem(string.Format("/myController/myAction/{0}", id));
            Response.RemoveOutputCacheItem(string.Format("/u/0/myController/myAction/{0}", id));
        }
Daniel
  • 9,312
  • 3
  • 48
  • 48