This week I have faced with one unexpected issue in Sitecore 8.1.
We are declaring few renderings on the layout using the Rendering method of the SitecoreHelper class in Sitecore.Mvc.dll.
@Html.Sitecore().Rendering("/sitecore/layout/Renderings/MyRendering")
The issue can be reproduced by setting the “Cacheable” to true and applying the “VaryBy” settings. In result I can see that the “Cacheable” is set but the rendering does not vary by anything I am trying to set there. And my rendering looks the same on all pages.
After some de-compiling and digging around I found that the CacheKey is not being properly generated due to wrong code in the Sitecore.Mvc.Helpers.SitecoreHelper class of Sitecore.Mvc dll.
The issue is that by some reason this method tries to read fields from the rendering item with these field names:
"Cache_Timeout" "Cache_VaryByData" "Cache_VaryByDevice" "Cache_VaryByLogin" "CacheKey" "Cache_VaryByParameters" "Cache_VaryByQueryString" "Cache_VaryByUser" "DataSource"
And yes, the rendering item does not have these fields. Correct names for some of them are:
"VaryByData" "VaryByDevice" "VaryByLogin" "VaryByParm" "VaryByQueryString" "VaryByUser" "Data Source"
And “Cache_Timeout” and “CacheKey” does not exist at all.
I have reported a bug to Sitecore support and they promised to investigate the issue. Meanwhile I have implemented my own helper class to render the Rendering from markup and the code is below.
using System.IO; using System.Web; using Sitecore.Data.Items; using Sitecore.Mvc.Extensions; using Sitecore.Mvc.Helpers; using Sitecore.Mvc.Pipelines; using Sitecore.Mvc.Pipelines.Response.RenderRendering; using Sitecore.Mvc.Presentation; namespace Helpers { public class SitecoreHelper { public static HtmlString Rendering(string renderingItemPathOrId) { return Rendering(renderingItemPathOrId, null); } public static HtmlString Rendering(string renderingItemPathOrId, object parameters) { return RenderRendering(GetRendering(string.Empty, parameters, "RenderingItemPath", renderingItemPathOrId)); } protected static Rendering GetRendering(string renderingType, object parameters, params string[] defaultValues) { var rendering = new Rendering { RenderingType = renderingType }; var index = 0; while (index < defaultValues.Length - 1) { rendering[defaultValues[index]] = defaultValues[index + 1]; index += 2; } if (rendering.RenderingItem != null) { // Changed field names var innerItem = rendering.RenderingItem.InnerItem; CopyPropertyFromDefinitionItem(rendering, innerItem, "Cacheable"); CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByData", "Cache_VaryByData"); CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByDevice", "Cache_VaryByDevice"); CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByLogin", "Cache_VaryByLogin"); CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByParm", "Cache_VaryByParameters"); CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByQueryString", "Cache_VaryByQueryString"); CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByUser", "Cache_VaryByUser"); CopyPropertyFromDefinitionItem(rendering, innerItem, "ClearOnIndexUpdate", "Cache_ClearOnIndexUpdate"); CopyPropertyFromDefinitionItem(rendering, innerItem, "Data Source", "DataSource"); CopyPropertyFromDefinitionItem(rendering, innerItem, "Model"); } if (parameters != null) { TypeHelper.GetProperties(parameters) .Each(pair => rendering.Properties[pair.Key] = pair.Value.ValueOrDefault(o => o.ToString())); } return rendering; } protected static void CopyPropertyFromDefinitionItem( Rendering rendering, BaseItem definitionItem, string fieldName, string propertyName = null) { var field = definitionItem.Fields[fieldName]; propertyName = propertyName ?? fieldName; if (field == null || field.Value.IsWhiteSpaceOrNull()) { return; } rendering[propertyName] = definitionItem[fieldName]; } protected static HtmlString RenderRendering(Rendering rendering) { var stringWriter = new StringWriter(); PipelineService.Get().RunPipeline("mvc.renderRendering", new RenderRenderingArgs(rendering, stringWriter)); return new HtmlString(stringWriter.ToString()); } } }
And then I replaced all usages of
@Html.Sitecore().Rendering("/sitecore/layout/Renderings/MyRendering")
to
@SitecoreHelper.Rendering("/sitecore/layout/Renderings/MyRendering")
If you using this method please double check that the caching settings are being properly set, otherwise use the code above.
That’s it Folks. 🙂
I just ran into this same issue within 8.1 MVC. Thanks for taking the time to share your discovery and providing a fix.
LikeLike
You are welcome 😉 This has not been fixed even in 8.1 u 3…
LikeLike
Also, checkout this package, ti will help to debug your cache keys. https://www.nuget.org/packages/Helpfulcore.CacheKeyProfiling/ The description is here. https://github.com/vhil/helpfulcore-cache-key-profiling
LikeLike
Thanks a lot for this solution. Do you have a Sitecore support ticket concerning this issue? Is there a hotfix available?
LikeLike
This issue has been registered as a bug. To track the future status, please use the reference number 93868 or 387950. More information about public reference numbers can be found here:
https://kb.sitecore.net/articles/853187
LikeLike
Thanks for the solution.
LikeLike