1

When I use outputcaching on an action method it is cached by full url, what i would like to do is cache the page but ignore some parts of the url.

Custom route defined in Global.asax:

routes.MapRoute(
  "Template",
  "Report/{reportid}/{reportname}/Template/{templateid}/{action}",
  new { controller = "Template", action = "Index" }
);

My template controller

public class TemplateController : Controller
{
   [OutputCache(Duration=60*60*2)]
   public ActionResult Index(Template template)
   {
      /* some code */
   }
}

For example when I go to the following URL's:

http://mywebsite.com/Report/789/cacheme/Template/5
-> cached for 2 hours based on the url

http://mywebsite.com/Report/777/anothercacheme/Template/5
-> also gets cached for 2 hours based on that url

What I would like is that the OutputCache ignores the reportname and reportid values so when I go to the above url's it returns the same cached version. Is this possible with the OutputCache attribute or will I have to write my custom OutputCache FilterAttribute?

2
  • Perhaps, one of the way could be to make reportname, reportid as parameters your method and then use VaryByParam for templateid only. Apart from that custom filter attribute will be the way to go! Commented Apr 14, 2011 at 8:40
  • I tried it but it still does return different cached versions for the requested template Commented Apr 14, 2011 at 10:06

1 Answer 1

1

Ended up with the following (inspired by http://blog.stevensanderson.com/2008/10/15/partial-output-caching-in-aspnet-mvc/):

 public class ResultCacheAttribute : ActionFilterAttribute
    {
        public ResultCacheAttribute()
        {

        }

        public string CacheKey
        {
            get;
            private set;
        }

        public bool AddUserCacheKey { get; set; }
        public bool IgnoreReport { get; set; }

        /// <summary>
        /// Duration in seconds of the cached values before expiring.
        /// </summary>
        public int Duration
        {
            get;
            set;
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            string url = "";
            foreach (var item in filterContext.RouteData.Values)
            {
                if (IgnoreReport)
                    if (item.Key == "reportid" || item.Key == "reportname")
                        continue;

                url += "." + item.Value;
            }
            if (AddUserCacheKey)
                url += "." + filterContext.HttpContext.User.Identity.Name;

            this.CacheKey = "ResultCache-" + url;

            if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
                this.CacheKey += "-ajax";

            if (filterContext.HttpContext.Cache[this.CacheKey] != null)
            {
                filterContext.Result = (ActionResult)filterContext.HttpContext.Cache[this.CacheKey];
            }
            else
            {
                base.OnActionExecuting(filterContext);
            }
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            filterContext.Controller.ViewData["CachedStamp"] = DateTime.Now;
            filterContext.HttpContext.Cache.Add(this.CacheKey, filterContext.Result, null, DateTime.Now.AddSeconds(Duration), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Default, null);

            base.OnActionExecuted(filterContext);
        }
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.