Sitecore - automated validation of MVC rendering DataSource
Posted 19 October 2014 by Marek Musielak
The project I'm working on now is based on Sitecore MVC. Lot of custom renderings, lot of configuration for them and lot of editable content. Most of the component data is stored in DataSource items and without DataSource item selected they make no sense and they don't provide any value. I was sick of placing if (DataSourceItem == null) { ... }
code in every single component so I automated this process using Sitecore <mvc.getRenderer>
pipeline.
Our assumption was simple: if a Sitecore MVC rendering requires DataSource Item to be selected, we configure its Datasource Template field. If the field is configured but DataSource item is not selected, the component is not valid and we don't want to display it in DisplayMode.Normal or DisplayMode.Preview, but editors should be able to see this component in DisplayMode.Edit and select proper DataSource for this component. That's why I added another processor to the Sitecore <mvc.getRenderer>
pipeline before GetViewRenderer
processor.
<sitecore> <pipelines> <mvc.getRenderer> <processor patch:before="*[@type='Sitecore.Mvc.Pipelines.Response.GetRenderer.GetViewRenderer, Sitecore.Mvc']" type="My.Assembly.Namespace.Pipelines.GetRenderer.GetMissingDatasourceRenderer, My.Assembly"> <ViewPath>/views/missingdatasource.cshtml</ViewPath> </processor> </mvc.getRenderer> </pipelines> </sitecore>
Code of this processor is really simple. It checks if DataSource Template is specified and if yes, then it validates if the DataSource item is selected and its template inherits from configured DataSource Template. If not, it sets Result of the pipeline to the ViewRenderer with configured ViewPath to the missing DataSource view cshtml
file.
public class GetMissingDatasourceRenderer : GetRendererProcessor { public string ViewPath { get; set; } public override void Process(GetRendererArgs args) { if (!args.Rendering.HasValidDatasource()) { args.Result = new ViewRenderer { ViewPath = ViewPath, Rendering = args.Rendering }; } } } public static class RenderingExtensions { public static bool HasValidDatasource(this Rendering rendering) { ReferenceField datasourceTemplateField = rendering.RenderingItem.InnerItem.Fields["Datasource Template"]; Item templateItem = datasourceTemplateField.TargetItem; if (templateItem == null) { // DataSource Template field empty - no need to check if DataSource item is set return true; } // check if the item is set and if its template inherits from configured template return rendering.Item.HasBaseTemplate(new TemplateItem(templateItem).FullName); } } public static class ItemExtensions { public static bool HasBaseTemplate(this Item item, string baseTemplateName) { if (item == null) { return false; } Template template = TemplateManager.GetTemplate(item); if (template == null) return false; return template.InheritsFrom(baseTemplateName); } }
Missing DataSource view cshtml
file checks if PageMode.IsPageEdit
and if yes, it displays message prompting for selecting DataSource and if no, it displays nothing.
@if (Sitecore.Context.PageMode.IsPageEditor) { <div> Select valid DataSource for @RenderingContext.Current.Rendering.RenderingItem.Name component </div> }
And that's it. Sitecore pipelines mechanism once again proved to be pluggable and extendible and allowed me to automate what I had to check in every single component before. I know that in your application setting DataSource Template field not necessarily means that DataSource item is required. You can always add a checkbox determining whether it is required or not.
Thanks for reading my blog post. If you have any comments or question, you can find me on twitter or send me an email.