December 13, 2015

Donut caching using Outputcache with DXA

Donut caching is the best way to cache an entire web page except for one or more parts of the web page. unfortunately post asp first version do not provide any good way to implement it.

I required to implement it in my project as i want all CMS pages to be cached except for the dynamic login and other sections. As DXA 1.2 has single method to process pages in Page Controller, and DxaEntity for component presentation. so if you apply OOTB Outputcache attribute to it. it will cache entire page including the dynamic sections.
While searching for solution i come across the DevTrends' library which enables Donut caching mvc solutions. i downloaded it from NuGet. using "install-package MvcDonutCaching" but could not use as it is because this library Serialize all the parameters passed in htmlAction method.

MvcHtmlString result = htmlHelper.Action(actionName, controllerName, parameters);

Code Change in Library
but problem with this is, the last parameter contains object of DD4T's ComponentPresentation class. so serialization fails while complaining about "no knowledge of this class". so i had to download the Source code of this library and add the reference of "DD4T.ContentModel" and then provided class in question as known type of Serialiser.

public ActionSettingsSerialiser(){_serialiser = new DataContractSerializer(typeof(ActionSettings), new[] { typeof(RouteValueDictionary),typeof(ComponentPresentation)});}

Code Change in DXA Library
Donut Library provides overloads of all methods in Helper.Action method, it provides a additional Boolean parameter which accepts whether to exclude the view from cache or not.
  • Refer the namespace of the library in Sdl.Web.Mvc.Html.HtmlHelperExtensions
  • Add optional parameter in following method.
    - MvcHtmlString DxaEntities(this HtmlHelper htmlHelper, int containerSize = 0, string excludeCache = null)
  • And following changes in  DxaEntity  
  • public static MvcHtmlString DxaEntity(this HtmlHelper htmlHelper, EntityModel entity, int containerSize = 0, string excludeCache=null)
  • bool excludeFromCache = (mvcData.ViewName.ToLower() == (excludeCache!=null?excludeCache.ToLower():string.Empty)); 
  • MvcHtmlString result = htmlHelper.Action(actionName, controllerName, parameters,excludeFromCache)

so i have added a optional parameter in the DxaEntities and DxaEntity Method, if any of the view is required to be excluded from the parent cache, just provide the name of the view.

It will match the viewName if it matches, then true is passed in the HtmlHelper.Action method and exclude this view from the cache.

Change in PageController or you can override the method.
[DonutOutputCache(CacheProfile = "Cache1Hour")]
        public virtual ActionResult Page(string pageUrl) 
web.config settings.
      <outputCache enableOutputCache="true"/>
          <add name="Cache1Hour" duration="0" location="Server" />

No comments: