0

I am working on trying to add custom Vary By options to renderings. I have created and added the custom fields to the Caching section on a rendering directly. This works fine for setting caching on the rendering definition, but the custom options are not showing up on a rendering instance.

I did some digging (via SO and DotPeek) and found references to needing to write my own custom field. The implementation would replace the version used by Sitecore OOTB: Sitecore.Shell.Applications.Layouts.DeviceEditor.CachingField, Sitecore.Client.

I did my own implementation of this field in an attempt to add support for two additional checkboxes. However, this custom implementation throws an Index Out of Bounds Exception each time I edit the component properties on a rendering:

Index Out of Bounds Exception

The culprit of this error stems from the code splitting the value of a private custom field variable.

public override void DoRender(HtmlTextWriter output)
{
    Assert.ArgumentNotNull((object)output, nameof(output));
    var id = this.customField.ID;
    var strArray = this.customField.Value.Split('|');
    output.Write("<div>");
    output.Write("<script language=\"javascript\" type=\"text/javascript\">");
    output.Write("\r\n        function scToggleCaching(id) {\r\n          var isDisabled = $F(id + '_cacheable') != '1';\r\n\r\n          $(id + '_varybydata').disabled = isDisabled;\r\n          $(id + '_varybydevice').disabled = isDisabled;\r\n          $(id + '_varybylogin').disabled = isDisabled;\r\n          $(id + '_varybyparameters').disabled = isDisabled;\r\n          $(id + '_varybyquerystring').disabled = isDisabled;\r\n          $(id + '_varybyuser').disabled = isDisabled;\r\n          $(id + '_clearonindexupdate').disabled = isDisabled;\r\n        }\r\n      ");
    output.Write("</script>");
    var isDisabled = strArray[0] == "0";
    RenderCaching(output, id, "Cacheable", strArray[0] == "1");
    RenderCheckBox(output, id + "_clearonindexupdate", "Clear on Index Update", true, strArray[1] == "1", isDisabled);
    RenderCheckBox(output, id + "_varybydata", "Vary by Data", true, strArray[2] == "1", isDisabled);
    RenderCheckBox(output, id + "_varybydevice", "Vary by Device", true, strArray[3] == "1", isDisabled);
    RenderCheckBox(output, id + "_varybylogin", "Vary by Login", true, strArray[4] == "1", isDisabled);
    RenderCheckBox(output, id + "_varybyparameters", "Vary by Parameters", true, strArray[5] == "1", isDisabled);
    RenderCheckBox(output, id + "_varybyquerystring", "Vary by Query String", true, strArray[6] == "1", isDisabled);
    RenderCheckBox(output, id + "_varybyuser", "Vary by User", true, strArray[7] == "1", isDisabled);

    RenderCheckBox(output, id + "varybypageitem", "Vary by Page Item", true, strArray[8] == "1", isDisabled);
    RenderCheckBox(output, id + "donotcache", "Do Not Cache", true, strArray[9] == "1", isDisabled);

    output.Write("</div>");
}

The first 8 elements of the split option are the default OOTB options. There is a missing ingress point into the field that I cannot seem to find. Does anyone have an idea on where else I need to plug in to get the extra vary bys thrown include the field value?

2
  • 1
    Do you really care about the custom Cache Options showing up in the Rendering Parameters/Control Properties? Is this something that your users are actually using to set cache options? It is much better, centralised and will mean your components being cached as defined by setting this on the Rendering item definition itself.
    – jammykam
    Commented Feb 8, 2021 at 2:05
  • 1
    Why not simply extend Sitecore.Mvc.Pipelines.Response.RenderRendering.GenerateCacheKey pipeline and override protected override string GenerateKey(Rendering rendering, RenderRenderingArgs args). Then in this method you could get your custom 'varyby' field and generate 'cachekey'. Example can be seen here leonardocunha.net/2019/10/15/…
    – Kamil C
    Commented Feb 8, 2021 at 11:09

1 Answer 1

1

Out of bounds exception is thrown because you forgot to extend LoadPostData which assembles 0|0|0|0|0|0|0|0. E.g.

 if (str1 == "1")
        str2 = str1 + "|" + CachingField.GetValue(id + "_clearonindexupdate") + "|" + CachingField.GetValue(id + "_varybydata") + "|" + CachingField.GetValue(id + "_varybydevice") + "|" + CachingField.GetValue(id + "_varybylogin") + "|" + CachingField.GetValue(id + "_varybyparameters") + "|" + CachingField.GetValue(id + "_varybyquerystring") + "|" + CachingField.GetValue(id + "_varybyuser");
      else
        str2 = str1 + "|0|0|0|0|0|0|0";

Which then later get's split by var strArray = this.customField.Value.Split('|'); in your DoRender method, if you count 0, you'll see that there's only 8 of them when you're trying to access non-existing 9th and 10th entry. However, fixing that is not the end. There's also RenderingEditorForm and RenderingParameters class in Sitecore.Shell.Applications.Layouts.DeviceEditor that you'll need to extend, as it's responsible for populating retrieving and setting actual values from/to rendering item. All in all, it's proving to be more painful than helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.