Introducing xWrap framework – Sitecore Experience Wrapper

After working for a while with Fortis as a stronly-typed wrapper framework for accessing Sitecore items as well as rendering engine I came up with the conclusion that it is not possible to use it in a solution built on Helix principles, as Fortis needs to know the whole template inheritance tree in order to generate the model correctly. Well, I guess there could be a way to make it work, I just didn’t find one. So I needed something smilar but compliant with Helix principles. There was of course a choice to use Glass mapper or Synthesis, however in my opinion, Fortis has a list of perfect architectural decisions and I wanted to have something similar.
That’s why I implemented my own xWrap mini-framework. Actually, I did that a while ago and have been using it on at least 5 projects with different Sitecore versions so I can tell that it is quite well tested, mature enough to share and well performing.
It has inherited a lot of approaches from Fortis, however has been even more simplified, de-coupled and finally helix compliant. If you are still interested, please read below about how to set it up and use 🙂

Here are some key features of xWrap:

  • built on a wrapper design pattern
  • super light-weight
  • uses only standard Sitecore API, no inventions
  • native support for Sitecore Experience Editor out of the box
  • compliant with helix principles and modular architecture
  • fully configurable through sitecore include config files
  • built with using default sitecore configuration factory and custom pipelines
  • provides functionality for strongly-typed wrapping fields
  • provides functionality for strongly-typed wrapping items
  • provides functionality for strongly-typed wrapping rendering parameters
  • provides functionality for MVC support based on strongly-typed view models
  • provides convenient field and item extensions
  • code-generation for habitat structure and Unicorn is available
  • provides safe item template and field type validation

Set up

Setting up xWrap is as easy as installing a nuget package.

Within helix modular architecture:

Install xWrap.Mvc nuget package to your project layer module (will include config files)
Install xWrap.Mvc.Framework nuget package to your feature or foundation layer module

This is it, the framework is ready to be used.

The framework consists of a set of nuget packages:

Code generation

Next obvious step in setting up would be enabling code-generation for Sitecore templates. The framework could be used without any code-generation mechanisms, however having automated code-generation for templates that we are designing does simplify our life a lot.
I made t4 templates based on habitat file/folder structure for Unicorn and they are available here.

What you need to do:

  1. place file to /codegen folder next to your scr folder.
  2. update dependencies in file to Rainbow and Sitecore.Kernel dll’s to match your version:
  3. copy to each helix project you want to generate template item wrappers for.
    Please note, this file needs to know your serialization folder. By default it uses habitat structure and will try to find your templates in “..\serialization\Templates” folder. If you have different structure, you may want to update this path in your file.
<#@ assembly name="$(SolutionDir)packagesRainbow.Core.2.0.0libnet452Rainbow.dll" #> 
<#@ assembly name="$(SolutionDir)packagesRainbow.Storage.Yaml.2.0.0libnet452Rainbow.Storage.Yaml.dll" #> 
<#@ assembly name="$(SolutionDir)packagesSitecore.Kernel.NoReferences.9.0.180604libNET452Sitecore.Kernel.dll" #>

For example, if I have my navigation feature project with name “Pintle.Feature.Navigation” and there is a data template “_Navigation” which is designed to be inherited by page templates:

The generated item wrapper for it will look like this:

namespace Pintle.Feature.Navigation.SitecoreTemplates
	using Sitecore.Data;
	using Sitecore.Data.Items;
	using Xwrap;
	using Xwrap.FieldWrappers.Abstractions;

	/// <summary>
	/// Item wrapper for items of template '_Navigation'.
	/// Template ID: {0F8C46C4-E777-46D0-89E0-225972998022}.
	/// Template path: /sitecore/templates/Feature/Navigation/Data/_Navigation.
	/// </summary>
    // ReSharper disable once InconsistentNaming
	// ReSharper disable once PartialTypeWithSinglePart
	public partial class _NavigationItem : ItemWrapper
		public _NavigationItem(Item item) : base(item)

		/// <summary>
		/// A wrapped 'single-line text' field for item field with name: 'Navigation title'.
		/// <returns><see cref="ITextFieldWrapper"/></returns>
		/// </summary>
		public ITextFieldWrapper NavigationTitle => this.WrapField<ITextFieldWrapper>(FieldNames.NavigationTitle);

		/// <summary>
		/// A wrapped 'checkbox' field for item field with name: 'Show in navigation'.
		/// <returns><see cref="ICheckboxFieldWrapper"/></returns>
		/// </summary>
		public ICheckboxFieldWrapper ShowInNavigation => this.WrapField<ICheckboxFieldWrapper>(FieldNames.ShowInNavigation);

		public static class Constants
			public static readonly TemplateID TemplateId = new TemplateID(new ID(TemplateIdString));
			public const string TemplateIdString = "{0F8C46C4-E777-46D0-89E0-225972998022}";

		public static class FieldNames
			public const string NavigationTitle = "Navigation title";
			public const string ShowInNavigation = "Show in navigation";

		public static class FieldIds
			public static ID NavigationTitle = new ID("{CA349367-5B39-4F87-8A6C-AD8B987191D9}");
			public static ID ShowInNavigation = new ID("{FFE61CDC-6969-4040-B801-E988695C16A0}");

This is how the simple item wrapper looks like.

  • It is inherited from Xwrap.ItemWrapper class, has a single constructor which takes Sitecore.Data.Item as a parameter – the item is being wrapped.
  • As you can see, the class is partial and that means you can extend it if you need by implementing a partial class.
  • The name of the template is “_Navigation” however the class name is “_NavigationItem” this has been done for leaving a naming “freedom” option to build your domain model if you may need to use “Navigation” name for that.
  • The class has three static classes inside with constants taken from Sitecore so you can access template ID, field names or IDs anywhere you need.
  • [TemplateId()] attribute is optional, but is being used to validate the item which is being wrapped against template id so you can be sure you are wrapping correctly in your code.
  • Each field is being wrapped into dedicated strongly-typed type.

Working with items

All strongly-typed item wrappers have to be inherited from Xwrap.ItemWrapper class which wraps some default Sitecore.Data.Item properties and provides functionality to wrap fields into strongly-typed representation.

The key object for working with item wrappers is Xwrap.ItemWrapperFactory
It is configured as a single instance:

      <itemWrapperFactory type="Xwrap.ItemWrapperFactory, Xwrap" singleInstance="true"/>

In order to get instance of ItemWrapperFactory, you can simply inject Xwrap.IItemWrapperFactory interface into yor constructor (if you working with native Sitecore DI container).
For Sitecore versions proir to Sitecore 8.2 – use the Xwrap.ItemWrapperFactory.Instance property.

If I want to wrap my current item as _NavigationItem I would use a very simple code:

var navItem = this.ItemWrapperFactory.WrapItem<_NavigationItem>(Sitecore.Context.Item);

In this case, if my Sitecore.Context.Item is instane of or inherited from _Navigation template – I will get a valid instance of my class. Otherwise – ItemWrapperFactory will return me null object.

xWrap framework also provides list of extensions to Sitecore.Data.Item so to do the same you can use

var navItem = Sitecore.Context.Item.WrapItem<_NavigationItem>();

This extension will call the instance of ItemWrapper factory and execute the same code inside.

You can always create an instance of the item wrapper using new operator:

var navItem = new _NavigationItem(Sitecore.Context.Item);

In this case, if Sitecore.Context.Item can’t be wrapped into target wrapper type – there will be an ItemWrappingException thrown.

If I want to get strongly typed direct children of an item which are inherited from my _Navigation template and the “Show in navigation” checkbox is checked, taking into account that there may be children of different templates as well, I can use a very simple code:

private IEnumerable<_NavigationItem>; GetDirectNavigationChildren(Item item)
    return this.ItemWrapperFactory.WrapChildren<_NavigationItem>(item)
        .Where(x => x.ShowInNavigation.Value);

or by using ItemWrapper.WrapChildren<TItemWrapper>() method:

private IEnumerable<_NavigationItem> GetDirectNavigationChildren(Item item)
    var itemWrapper = this.ItemWrapperFactory.WrapItem<ItemWrapper>(item);
    return itemWrapper?.WrapChildren<_NavigationItem>().Where(x => x.ShowInNavigation.Value)
        ?? Enumerable.Empty<_NavigationItem>();

or by using an extension method:

private IEnumerable<_NavigationItem> GetDirectNavigationChildren(Item item)
    return item.WrapChildren<_NavigationItem>().Where(x => x.ShowInNavigation.Value);

Working with fields

xWrap framework implements a set of strongly-typed field wrappers for each Sitecore field type that comes out of the box.
All field wrappers implement Xwrap.FieldWrappers.Abstractions.IFieldWrapper<out TReturnType> interface:

public interface IFieldWrapper<out TReturnType> : IFieldWrapper
    string RawValue { get; }
    TReturnType Value { get; }

Therefore each field wrapper has RawValue property – the original Sitecore field value and a Value property which is strongly typed. Each field wrapper knows how to extract and cast Sitecore field value to its type. For example field wrapper for date time field implements IFieldWrapper<DateTime>:

public interface IDateTimeFieldWrapper : IFieldWrapper<DateTime>

There is also a base class that each field wrapper type inherits Xwrap.FieldWrappers.FieldWrapper which implements common methods and properties for all wrapper types.
Similar to ItemWrapperFactory, there is Xwrap.IFieldWrapperFactory type which is also registered in DI container and configured in include folder:

		<fieldWrapperFactory type="Xwrap.FieldWrapperFactory, Xwrap" singleInstance="true">
			<param name="cacheService" ref="xWrap/cacheService"/>

There is an option to wrap fields without even having the ItemWrapper class by using FieldWrapperFactory:

var showInNavigationField = this.FieldWrapperFactory.WrapField<ICheckboxFieldWrapper>(Sitecore.Context.Item, "Show in navigation");

Or by using an item extension method:

var showInNavigationField = Sitecore.Context.Item.CheckboxField("Show in navigation");

or by using field extension method:

var showInNavigationField = Sitecore.Context.Item.Fields["Show in navigation"].AsCheckboxField();

Obvously, having pre-generated item wrappers for your templates is much more convenient as they already know how to wrap each field, however in old solutions wrapping on field level would be the minimal change to start using strongly typed way of working with fields.

Architecture and extensibility

The framework is build using native Sitecore configutaion factory and a few custom pipelines. Have a look at your App_Config/Include/xWrap folder and you will find all the configurations:

Each key object is configured in the include config file which leaves the option of extending and replacement of their implementation. I have also tried to make all methods as virtual which enables respective extensibility options.
Field wrapper factory uses a custom pipeline for wrapping the field into respective field wrapper type that can be found here. And for example if you have built your custom field type, you can create a field wrapper for it and add to the pipeline so you can use it in a strongly-typed representation.

xWrap framework provides a very convenient way for working with MVC renderings as well and this part needs a separate post which I will write shortly.