@Html.Sitecore().Rendering(pathOrId) does not apply “VaryBy” settings

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. 🙂

Advertisements

7 thoughts on “@Html.Sitecore().Rendering(pathOrId) does not apply “VaryBy” settings

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s