Sitecore 7.2 MVC and DMS

2.3k views Asked by At

I am trying to setup DMS on Sitecore 7.2 using MVC. I am able to set personalization rules via the Page Editor but the rules do not run when I view the page as a normal users. I have checked the following:

  1. Analytics.Enabled is set to true
  2. @Html.Sitecore().VisitorIdentification() has been added to the main layout
  3. The analytics DB is setup
  4. No errors are showing in the logs.
  5. I have enabled the config file Sitecore.MvcAnalytics.config
  6. analytics is enabled for the site.
  7. My conditions work in WebForms, it is only MVC that doesn't work.

We have narrowed the problem down to Controller Renderings, our solution works for View Renderings. Has anyone made personalisation work with Controller Renderings? We have replicated this problem in a vanilla SC instance.

Here is a video of our problem:

http://screencast.com/t/1nGwUINJLZO

This is a screenshot of my controller code:

enter image description here

And the components on the page:

enter image description here

We have tried to setup a test with the minimum amount of interference.

3

There are 3 answers

1
Michael Edwards On BEST ANSWER

Problem

The problem was caused by the Sitecore.Forms.Mvc.config file. I hadn't mentioned WFFM in my original question because I assumed that it wouldn't affect DMS.

When you enable DMS without WFFM the getRenderer pipeline looks like this:

<mvc.getRenderer patch:source="Glass.Mapper.Sc.Mvc.config">
    <processor type="Sitecore.Mvc.Analytics.Pipelines.Response.GetRenderer.CustomizeRendering, Sitecore.Mvc.Analytics" patch:source="Sitecore.MvcAnalytics.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetViewRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetItemRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetXsltRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetControllerRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetMethodRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetUrlRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetDefaultRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
</mvc.getRenderer>

You can see here that the first entry is a processor that analytics inserts to control personalisation. If we now enable the Sitecore.Forms.Mvc.config this pipeline changes to this:

<mvc.getRenderer patch:source="Glass.Mapper.Sc.Mvc.config">
    <processor type="Sitecore.Forms.Mvc.Pipelines.GetFormControllerRenderer, Sitecore.Forms.Mvc" patch:source="Sitecore.Forms.Mvc.config"/>
    <processor type="Sitecore.Mvc.Analytics.Pipelines.Response.GetRenderer.CustomizeRendering, Sitecore.Mvc.Analytics" patch:source="Sitecore.MvcAnalytics.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetViewRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetItemRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetXsltRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetControllerRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetMethodRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetUrlRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
    <processor type="Sitecore.Mvc.Pipelines.Response.GetRenderer.GetDefaultRenderer, Sitecore.Mvc" patch:source="Sitecore.Mvc.config"/>
</mvc.getRenderer>

Notice that the WFFM Forms MVC entry inserts itself at the start of the pipeline. This causes problems because it returns a rendering:

protected override Renderer GetRenderer(Rendering rendering, GetRendererArgs args)
{
  if (args.Rendering.RenderingItem.ID != IDs.FormMvcInterpreterID)
    return base.GetRenderer(rendering, args);
  Tuple<string, string> controllerAndAction = this.GetControllerAndAction(rendering, args);
  if (controllerAndAction == null)
    return (Renderer) null;
  string str1 = controllerAndAction.Item1;
  string str2 = controllerAndAction.Item2;
  FormControllerRenderer controllerRenderer = new FormControllerRenderer();
  controllerRenderer.ControllerName = str1;
  controllerRenderer.ActionName = str2;
  return (Renderer) controllerRenderer;
}

The CustomiseRendering processor then does nothing because there is a returned result, therefore no personalization is performed:

public override void Process(GetRendererArgs args)
{
  Assert.ArgumentNotNull((object) args, "args");
  if (args.Result != null || args.Rendering == null || string.IsNullOrEmpty(args.Rendering["RenderingXml"]))
    return;
  CustomizeRenderingArgs args1 = new CustomizeRenderingArgs(args.Rendering);
  args.Result = PipelineService.Get().RunPipeline<CustomizeRenderingArgs, Renderer>("mvc.customizeRendering", args1, (Func<CustomizeRenderingArgs, Renderer>) (pipelineArgs => pipelineArgs.Renderer));
}

Cause:

This is caused by the order that the MVC, Web Forms and Analytics configs are loaded. By default they are loaded in this order:

  1. Sitecore.Forms.Mvc.config
  2. Sitecore.Mvc.config
  3. Sitecore.MvcAnalytics.config

This is the correct order.

Solution:

The solution is to rename the Sitecore.Forms.Mvc.Config to y.Sitecore.Forms.Mvc.config to force it to be loaded last.

2
Dag Sigvaldsen On

I can not get the @Html.Sitecore().VisitorIdentification() to work. We just put the

<sc:visitoridentification runat="server" /> 

before the

</head> 

Have you looked at your source to see if @Html.Sitecore().VisitorIdentification() includes it?

0
Pavel Veller On

I don't see how it can be specific to controller renderings to be honest. In Sitecore MVC controller and view renderings alike follow the same pipeline path. More specifically, a variation based on A/B (aka MVT) test or personalization rules is picked as a first step in mvc.getRenderer pipeline. You should have

Sitecore.Mvc.Analytics.Pipelines.Response.GetRenderer.CustomizeRendering

in there coming from Sitecore.MvcAnalytics.config. When it runs it will trigger mvc.customizeRendering. I guess what I am saying is - Personalization happens before a particular renderer is picked based on your rendering's type. You may want to look at Sitecore.Mvc.Analytics.Pipelines.Response.CustomizeRendering.Personalize in Sitecore.Mvc.Analytics to see how exactly Sitecore applies your personalization rules.

I know I am not answering your question per se but here's what I would do myself:

  • Make sure the rendering in question runs its natural course (e.g. you are not creating a Rendering object on which you set .Renderer manually, not monkey patching MVC contexts, etc.)
  • Confirm the outer rendering (in case your controller rendering is nested within another rendering) is not set to be cached (if it is, Sitecore won't call the rendering pipeline on the inner renderings again once the outer rendering has been cashed. I know it's obvious but I've seen people surprised by it)
  • Double check that personalization rules are recorded just like you think they are by inspecting the raw value of the item's __Renderings field in the published item (personalization doesn't run in Preview, only runs when PageMode.IsNormal).
  • Make sure you are not sending the razor view that ends up generating markup through yet another renderRendering pipeline when you return from your controller. If you wrap it with RenderingView, for example, it would run through its own pipeline and would have its own RenderingContext and its own Rendering object. Personalization will change the datasource on your controller rendering object and your @Html.Sitecore().Field() may be talking to a different Rendering.Item than you need (log your Rendering.Item in your controller and do the same in your razor to see what's going on). I blogged about some of it last week (http://jockstothecore.com/sitecore-mvc-item-maze/) and you will probably see the rendering pipelines sequence if you Debug in Page Editor.
  • If everything looks right and rules still mysteriously don't fire I would most likely use the trick I learned very recently and would put Sitecore in debug (http://bilyukov.com/debugging-sitecore-dotpeek/). Helped more than once to get to the bottom of things.