Sitecore: MVC  fallback device

Implementation of layout fallback device in Sitecore MVC

Sometimes when you creating mobile versions of a site, you could decide to show some page from desktop version and do not create mobile layout for them (e.g. they are less important than other pages or not visited frequently). Sitecore has setting for that called Fallback Device. However, when you are working with MVC layout it is not really working. Nice moment over here is that it is really easy to enable it.

MVC layout background

In order to add fix you need to understand how Sitecore understands that you need to switch to MVC and find right place for fix. All magic starts in httpRequestBegin processors section:

<processor type="Sitecore.Mvc.Pipelines.HttpRequest.TransferMvcLayout, Sitecore.Mvc" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.LayoutResolver, Sitecore.Kernel']" />

When you page item is resolved and we could get information about its layout Sitecore understands that you are using .cshtml layout and transfer processing to MVC.

During the processing Sitecore MVC execute following section:

<mvc.getPageRendering>
<processor type="Sitecore.Mvc.Pipelines.Response.GetPageRendering.GetLayoutRendering, Sitecore.Mvc"/>
</mvc.getPageRendering>

This is exactly the code we were searching for ☺

Pipeline upgrade

namespace Example
{   
    using System.Collections.Generic;
    using System.Linq;

    using Sitecore;
    using Sitecore.Data.Items;
    using Sitecore.Mvc.Extensions;
    using Sitecore.Mvc.Pipelines.Response.GetPageRendering;
    using Sitecore.Mvc.Presentation;

    public class GetLayoutRenderingWithFallback : GetLayoutRendering
    {
        protected override Rendering SelectLayoutRendering(List<Rendering> renderings, GetPageRenderingArgs args)
        {
            var result = base.SelectLayoutRendering(renderings, args);

            if (result != null)
            {
                return result;
            }

            var device = Context.Device;
            while (device != null)
            {
                var b = device.ValueOrDefault((DeviceItem d) => d.ID.ToGuid());
                foreach (var current in renderings.Where(current => current.DeviceId == b && current.RenderingType == "Layout"))
                {
                    // set fallback device as current.
                    Context.Device = device;
                    return current;
                }

                device = Context.Device.FallbackDevice;
            }

            return null;
        }
    }
}

We inherit our pipeline from sitecore one and add some logic to handle cases when base implementation was not able to resolve layout (see source).

And the last thing that we need to do is to replace standard pipeline with Sitecore config patch. We are done.

No comments :

Post a Comment