Content Output Caching – Part 2

In the previous post you learned about how to install the output caching module in a EPiServer project. Now it is time to see it in action. First, I created a MVC application that displays a list of pages, so by default, each time the user invokes the controller action to see records, the application loops through the entire process and executes queries to the index. And this can actually decrease the application performance. This is how the page looks like:

List of page items.

We can take advantage of the “MvcOutputCache” attribute that avoids executing expensive work each time the user invokes the controller action. See the following example:

public class MyController : PageController
{
   [MvcOutputCache]
   public ActionResult Index(Page currentPage)
   {
      var model = PageViewModel.Create(currentPage);
      return View(model);
   }
}

Here the view page is retrieved from the cache instead of invoking the controller action and doing redundant work. In this example the output cache is configured by default with the following settings:

  • Vary by user.
  • Vary by host (in case web site served on multiple domains).
  • Vary by query string.
  • Invalidate cache on post is disabled (this might be useful when a user updates information).

Other variants for MvcOutputCache are:

// Disable vary by user and host
[MvcOutputCache(VaryByUser = false, VaryByHost = false)]

// Scenario: a user updates information; they should see their changes immediately; therefore, invalidate cache for that user
[MvcOutputCache(InvalidateUserCacheOnPost = true)]

// Cache valid only for anonymous users.
[MvcOutputCache(AnonymousOnly = true)]

// Vary by cookie
[MvcOutputCache(VaryByCookie = "cookieName")]

// Enable debug mode
[MvcOutputCache(DebugMode = true)]

Enabling debug mode allows you to check if the content is actually retrieved from the action method or the cache. The image below shows the log entries of my site:

To clear the cache you can do it manually by clicking the button “Clear Cache” in the CMS.

Or automatically by coding an initialization module to remove the cache every time a user publish content. For example:

[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class PublishEventInitializationModule : IInitializableModule
{
	private static Injected<ISynchronizedObjectInstanceCache> _cache;

    public void Initialize(InitializationEngine context)
    {
        //Add initialization logic, this method is called once after CMS has been initialized
        var contentEvents = ServiceLocator.Current.GetInstance<IContentEvents>();
        contentEvents.PublishingContent += contentEvents_PublishingContent;
    }
 
    void contentEvents_PublishingContent(object sender, EPiServer.ContentEventArgs e)
    {
        // Clear the cache here		
		_cache.Service.RemoveLocal("MvcOutputCache");
    }    

	public void Uninitialize(InitializationEngine context)
    {
        // Add uninitialization logic
        var contentEvents = ServiceLocator.Current.GetInstance<IContentEvents>();
        contentEvents.PublishingContent -= contentEvents_PublishingContent;
    }
}

Thanks to Jake Jones for the suggestion of using a master key for caching content.

6 thoughts on “Content Output Caching – Part 2

  1. Pingback: Content Output Caching – Part 1 – PowerBuilder

  2. I don’t know if you’re building up to this by the name of the article but Episerver has a specific attribute called [ContentOutputCache] for which extends the standard controller caching using the synchronized cache provider, this give the caching awareness of the content type so that any CMS changes invalidate the cache. http://www.jondjones.com/learn-episerver-cms/episerver-developers-guide/episerver-caching/episerver-caching-the-output-cache-explained The only down side with the caching approach at the page level is it’s not that great at knowing about changes to blocks inside the page. Personally we use a donut whole caching technique where you can cache blocks at the controller level based upon the content changes. This gives a lot of flexibility for complex caching scenarios.

    Like

    1. This module is built based on the Episerver attribute [ContentOutputCache], and it extends functionality to allow caching at the block level, VaryByCookie, VaryByLogin, VaryByCustom, and VaryByHost. I also created a button in the module to clear the cache manually, but you could clear the cache by coding an initialization module.

      Like

      1. Ah I see, I didn’t find it clear from the initial blog post you were extending the original attribute. We have done a similar think for the block level caching with a custom attribute as personally I don’t like caching at the page level especially with the ContentOutputCache attribute doesn’t out of the box support block personalization. We’ve extended our block level donut caching with Episerver’s syncrozined caching to support nested content areas, sub blocks and any contentreference properties so they all force block level cache invalidation. It always interesting to see other people’s mechanisms

        Like

  3. Jake Jones

    Hi Francisco, pretty interesting project!

    I think it would be a great add if you respected the Episerver httpCacheExpiration parameter. Also, I can’t see a mechanism that expires your output caching based on content expiration?

    Finally, I notice your example of clearing the cache when publishing will actually purge the entire synchronized cache across all servers regardless of which piece of content is changed—that could have some serious performance ramifications. Not sure if you already support clearing the output cache of relevant content? It not, it could be worth investigating the use of master keys…

    Like

    1. Hi Jake, thank you for your feedback.
      If your content reaches the expiration date, EPiServer will throw a 404 response code, so I considered that it was not necessary to validate that in the Action Filter Attribute. Regarding the httpCacheExpiration parameter, I will take a look.

      Like

Leave a reply to Jake Jones Cancel reply