5

This isn't a question I've seen around, usually it's 'EPiServer isn't clearing the output cache'. I'm trying to achieve the opposite. Each time a page is published the entire cache is dropped and as the client publishes several times a day, this is frustrating.

I'm using the [ContentOutputCache] attribute and tried to implement a httpCacheVaryByCustom rule with an accompanying scheduled task in EPiServer to invalidate the cache when we decide to i.e. bundle updates together and invalidate at a predetermined time.

I've tested this rule and it works using:

public override string GetVaryByCustomString(HttpContext context, string custom)

I was under the impression that by using this type of caching rule it would stop EPiServer dumping my cache whenever something is published / media uploaded.

It doesn't though is there a way to stop this from happening?

I've had success by using the standard [OutputCache] with the same custom string rule the only problem with this is that editors will always see a cached version of the page they are editing.

The application settings I have in my web.config for EPiServer are:

<applicationSettings globalErrorHandling="Off" operationCompatibility="DynamicProperties" uiSafeHtmlTags="b,i,u,br,em,strong,p,a,img,ol,ul,li" disableVersionDeletion="false" 
                     httpCacheability="Public" uiEditorCssPaths="~/assets/css/styles.css, ~/assets/css/editor.css" urlRebaseKind="ToRootRelative" 
                     pageUseBrowserLanguagePreferences="false" uiShowGlobalizationUserInterface="false" subscriptionHandler="EPiServer.Personalization.SubscriptionMail,EPiServer" 
                     uiMaxVersions="20" pageValidateTemplate="false" utilUrl="~/util/" 
                     uiUrl="~/EPiServer/CMS/" httpCacheExpiration="01:00:00"  httpCacheVaryByCustom="invalidateSiteCache" />
Electric Sheep
  • 3,867
  • 1
  • 29
  • 38

1 Answers1

5

A custom GetVaryByCustomString function will determine when the cache is invalidated, but any request for content that is using the ContentOutputCache is checked against a master cache key Episerver.DataFactoryCache.Version. This version number is incremented any time content is published, updated etc, and the cache is invalidated if the version number is changed.

To understand what you need to do, I recommend using a decompiler (e.g. DotPeek) and looking at the ContentOutputCacheAttribute and OutputCacheHandler classes in the Episerver dll.

You will need to:

  1. Derive a new handler from EPiServer.Web.OutputCacheHandler
  2. Create an alternative method to ValidateOutputCache(...) that still calls OutputCacheHandler.UseOutputCache(...) but ignores the cache version number
  3. Derive a new attribute from ContentOutputCacheAttribute
  4. Override the method OnResultExecuting(ResultExecutingContext filterContext) using the same logic as the current method (this is where a decompiler is useful), but that adds a callback to your new validate method instead of the current one. Unfortunately we can't inject the new handler because the validate method is passed statically.

e.g.

public override void OnResultExecuting(ResultExecutingContext filterContext)
{        
    // Rest of method
    filterContext.HttpContext.Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(CustomOutputCacheHandler.CustomValidateOutputCache), (object) tuple);
}
  1. Use the new attribute in place of [ContentOutputCache]
Electric Sheep
  • 3,867
  • 1
  • 29
  • 38
  • Thanks for your answer Ollie, finally I now know why and how EPiServer is dropping the cache. The only problem using the [OutputCache] attribute is that editors will be seeing a cached version of a page after they have published any changes to it. Unless we drop the cache after a publish which is what I'm trying to avoid. What I'm after is the ability to keep EPiServers cache functionality that allows editors to view the site uncached while the current live is remains cached. I just want to stop the cache dropping after each publish the solution seems quite elusive. – Daniel Pickford May 12 '16 at 13:51
  • Sorry, I misread that part. Think it still might be possible, I will updated my answer. – Electric Sheep May 12 '16 at 14:10
  • Thanks Ollie that would be brilliant! – Daniel Pickford May 12 '16 at 14:15
  • Thank you for your time Ollie I'll give this a try! :D – Daniel Pickford May 12 '16 at 15:17
  • 1
    Hi Ollie, I feel like we are close to cracking this but it's still not working quite right. In debug mode I can see my new CustomValidateOutputCache being called and behaving as expected returning cache valid after a publish. However the cache is still dropped... somehow. Using DotPeek (thanks for that) I'm thinking that maybe I also need to override SetCachePolicy? What do you think? I'm wondering if EPiServer is emptying the cache elsewhere on a publish. – Daniel Pickford May 18 '16 at 16:42
  • 1
    I've just seen this Under the Publish method in the EPiServer.dll this._cacheManager.RemoveLocal(DataFactoryCache.ContentVersionCacheKey(saveEventArgs.ContentLink)); I wonder if this is the culprit. – Daniel Pickford May 18 '16 at 16:50
  • @DanielPickford In the `DataFactoryCache.Intialize` method, an `IContentEvents` parameter is passed which is used to add event handlers to manipulate the cache for a variety of events e.g. save, publish, delete. I wonder if you could somehow remove these events manually. Potentially getting it using the service locator or dependency injection - `ServiceLocator.Current.GetInstance()`? – Electric Sheep May 18 '16 at 17:07