protected override void RenderContentAreaItem( HtmlHelper htmlHelper, ContentAreaItem contentAreaItem, string templateTag, string htmlTag, string cssClass) { var content = contentAreaItem.GetContent(ContentRepository); if (content == null) { return; } var serialisedContent = EpiServerDonutHelper.SerializeBlockContentReference(content); using (var textWriter = new StringWriter()) { var cutomHtmlHelper = EpiServerDonutHelper.CreateHtmlHelper(htmlHelper.ViewContext.Controller, textWriter); EpiServerDonutHelper.RenderContentData(cutomHtmlHelper, content, string.Empty); var tagBuilder = CreateContentAreaSeperatorHtmlTags(contentAreaItem, htmlTag, cssClass); var epiServerHtml = EpiServerDonutHelper.CreateContentAreaDonutTag(tagBuilder, serialisedContent, textWriter.ToString()); htmlHelper.RenderXhtmlString(new XhtmlString(epiServerHtml)); } }
public static void DonutForContent(this HtmlHelper htmlHelper, IContent content) { var serialisedContent = EpiServerDonutHelper.SerializeBlockContentReference(content); using (var textWriter = new StringWriter()) { var cutomHtmlHelper = EpiServerDonutHelper.CreateHtmlHelper(htmlHelper.ViewContext.Controller, textWriter); EpiServerDonutHelper.RenderContentData(cutomHtmlHelper, content, string.Empty); var outputString = string.Format("<!--Donut#{0}#-->{1}<!--EndDonut-->", serialisedContent, textWriter); var htmlString = new XhtmlString(outputString); htmlHelper.RenderXhtmlString(htmlString); } }
public string ReplaceDonutHoleContent(string content, ControllerContext filterContext, OutputCacheOptions options) { if (filterContext.IsChildAction && (options & OutputCacheOptions.ReplaceDonutsInChildActions) != OutputCacheOptions.ReplaceDonutsInChildActions) { return(content); } return(DonutHoleRegex.Replace(content, match => { var contentReference = JsonConvert.DeserializeObject <ContentReference>(match.Groups[1].Value); if (contentReference == null) { return null; } var htmlToRenderWithoutDonutComment = new StringBuilder(); using (var stringWriter = new StringWriter()) { var htmlHelper = EpiServerDonutHelper.CreateHtmlHelper(filterContext.Controller, stringWriter); var repo = ServiceLocator.Current.GetInstance <IContentRepository>(); var epiContentToRender = repo.Get <IContent>(contentReference); var openTag = OpenTagRegex.Match(match.Groups[1].ToString()).Groups[1].ToString(); if (!string.IsNullOrEmpty(openTag)) { htmlToRenderWithoutDonutComment.Append(openTag); } EpiServerDonutHelper.RenderContentData(htmlHelper, epiContentToRender, string.Empty); htmlToRenderWithoutDonutComment.Append(stringWriter.ToString()); var closeTag = CloseTagRegex.Match(match.Groups[1].ToString()).Groups[1].ToString(); if (!string.IsNullOrEmpty(closeTag)) { htmlToRenderWithoutDonutComment.Append(closeTag); } } return htmlToRenderWithoutDonutComment.ToString(); })); }
/// <summary> /// Executes the callback. /// </summary> /// <param name="context">The context.</param> /// <param name="hasErrors">if set to <c>true</c> [has errors].</param> private void ExecuteCallback(ControllerContext context, bool hasErrors) { // Custom code var cacheKey = EpiServerDonutHelper.GenerateUniqueCacheKey(context); if (string.IsNullOrEmpty(cacheKey)) { return; } var callback = context.HttpContext.Items[cacheKey] as Action <bool>; if (callback != null) { callback.Invoke(hasErrors); } }
/// <summary> /// Called after an action result executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnResultExecuted(ResultExecutedContext filterContext) { if (CacheSettings == null) { return; } var cacheKey = EpiServerDonutHelper.GenerateUniqueCacheKey(filterContext); // See OnActionExecuting ExecuteCallback(filterContext, filterContext.Exception != null); // If we are in the context of a child action, the main action is responsible for setting // the right HTTP Cache headers for the final response. if (!filterContext.IsChildAction) { CacheHeadersHelper.SetCacheHeaders(filterContext.HttpContext.Response, CacheSettings); } }
/// <summary> /// Called before an action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { CacheSettings = BuildCacheSettings(); // Custom Code var cacheKey = EpiServerDonutHelper.GenerateUniqueCacheKey(filterContext); // If we are unable to generate a cache key it means we can't do anything if (string.IsNullOrEmpty(cacheKey)) { return; } // Are we actually storing data on the server side ? if (CacheSettings.IsServerCachingEnabled) { CacheItem cachedItem = null; // If the request is a POST, we lookup for NoCacheLookupForPosts option // We are fetching the stored value only if the option has not been set and the request is not a POST if ( (CacheSettings.Options & OutputCacheOptions.NoCacheLookupForPosts) != OutputCacheOptions.NoCacheLookupForPosts || filterContext.HttpContext.Request.HttpMethod != "POST" ) { cachedItem = OutputCacheManager.GetItem(cacheKey); } // We have a cached version on the server side if (cachedItem != null) { // We inject the previous result into the MVC pipeline // The MVC action won't execute as we injected the previous cached result. var donutReplacedHtml = DonutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, filterContext, CacheSettings.Options); Logger.ErrorFormat("PRE DONUT HTML FROM CACHE {0} {1}", cacheKey, cachedItem.Content); Logger.ErrorFormat("DONUT REPLACED HTML FROM CACHE {0} {1}", cacheKey, donutReplacedHtml); filterContext.Result = new ContentResult { Content = donutReplacedHtml, ContentType = cachedItem.ContentType }; } } // Did we already injected something ? if (filterContext.Result != null) { return; // No need to continue } // We are hooking into the pipeline to replace the response Output writer // by something we own and later eventually gonna cache var cachingWriter = new StringWriter(CultureInfo.InvariantCulture); var originalWriter = filterContext.HttpContext.Response.Output; filterContext.HttpContext.Response.Output = cachingWriter; // Will be called back by OnResultExecuted -> ExecuteCallback filterContext.HttpContext.Items[cacheKey] = new Action <bool>(hasErrors => { // Removing this executing action from the context filterContext.HttpContext.Items.Remove(cacheKey); // We restore the original writer for response filterContext.HttpContext.Response.Output = originalWriter; if (hasErrors) { return; // Something went wrong, we are not going to cache something bad } var itemToRenderWithDonuts = cachingWriter.ToString(); var originalWriterString = originalWriter.ToString(); // Now we use owned caching writer to actually store data var cacheItem = new CacheItem { Content = itemToRenderWithDonuts, ContentType = filterContext.HttpContext.Response.ContentType }; var donutRemovedHtml = DonutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext, CacheSettings.Options); filterContext.HttpContext.Response.Write(donutRemovedHtml); Logger.ErrorFormat("PRE DONUT HTML LIVE {0} {1}", cacheKey, cacheItem.Content); Logger.ErrorFormat("DONUT REPLACED HTML LIVE {0} {1}", cacheKey, donutRemovedHtml); if (CacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200) { OutputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(CacheSettings.Duration)); } }); }