ModelMapping

Programming Sitecore using ASP.NET MVC is straightforward, but full of uninteresting concerns. The syntax for getting Item Field values onto the page is tedious and prone to “spelling errors” that can only be picked up at runtime.

Some folks have addressed this last bit by bringing in ORM frameworks and code generation. Unfortunately, these “Evil Wizards” bring a whole host of problems associated with legibility, predictability, long-term maintenance, and in many cases even more burdensome syntax.

Constellation.Foundation.ModelMapper is meant to address these problems:

  • No need for T4 templates or other code generation technology
  • No need for TDS, Unicorn, or other Item serialization technology
  • No “overrides” of stock Sitecore rendering and data access behavior. It’s stock Sitecore across the board to maximize flexibility and compatibility with other frameworks.
  • Reduce the keystroke burden to get a Field to render on page.
  • Centralize the location of spelling mistakes that might show up at runtime.
  • Use a declaritive syntax for handling what’s “available for editing” on a given Rendering.
  • Bring the simple beauty of Entity Framework models to Sitecore without the complexity of proxy classes, inversion of control or dependency injection.

Core Principles

The ModelMapping component is designed to support the Model-View-ViewModel (MVVM) architecture common in ASP.NET MVC projects. It is not an ORM, and ViewModels (aside from Page/Experience Editor support) are essentially “read only”.

The ModelMapper class (the main feature of this component) will convert a Sitecore Item, field-by-field, into a plain-old-class-object (POCO) that you designed.

This component was heavily influenced by AutoMapper and paraphrases some of its basic syntax and hierarchy-flattening principles. Constellation’s model mapping capabilities are not as advanced; they are limited to generating ViewModel instances from Sitecore Item instances.

The Basic Concept

because all developers need convincing…

Turn this:
@Html.Sitecore().Field("Field Name", someItem)

or this:
@Editable(someItem, x => x.Field_Name)

Into this:
@Model.FieldName

Or sometimes this:
@Html.Raw(Model.FieldName)

If you’re using generated classes with Glass or Synthesis, you might have the following scenario:

var referencedItem = SitecoreContext.Cast(sourceItem.Reference_Field_Name.TargetItem);

@Editable(referencedItem, x => x.Some_Field_Name)

With Constellation ModelMapping, we can condense that whole mess to this:

@sourceItem.ReferenceFieldName.SomeFieldName

Similarly for list fields, we can take this kind of code:

var someList = new List();

foreach (var item in sourceItem.ListField)
{
    someList.Add(SitecoreContext.Cast(item));
}

foreach (var listMember in someList)
{
	@Editable(listMember, x => x.Field_Name)
}

And consolidate it to something like this:

foreach (var listModel in Model.ListField)
{
        @listModel.FieldName
}

A Brief Example

Here’s an archetypical Item Template as found on virtually every site out there today:

PressReleaseTemplateBuilder

Obviously we’re going to need a rendering to display all of this information on page, so let’s create our ViewModel:

public class PressRelease
{
    public string MastheadImage { get; set; }

    public string PageHeading { get; set; }

    public Author Author { get; set; }

    public DateTime ReleaseDate { get; set; }

    public string Summary { get; set; }

    public string BodyCopy { get; set; }
}

I prefer Controller renderings, but you could use this code directly on the View if you were so inclined. We have two options for translating the Item into our ViewModel:

Option 1

using Constellation.Foundation.ModelMapping;
using Sitecore;
using Sitecore Data;

namespace Examples
{
    public class SomeController : Controller
    {
        private PressRelease GetViewModel(ID id, Language language)
        {
            var item = Database.GetItem(id, language);
            var viewModel = new PressRelease()

            Mappper.MapTo(item, viewModel);

            return viewModel;
        }
    }
}

Option 2

using Constellation.Foundation.ModelMapping;
using Sitecore;
using Sitecore Data;

namespace Examples
{
    public class SomeController : Controller
    {
        private PressRelease GetViewModel(ID id, Language language)
        {
            var item = Database.GetItem(id, language);
            return Mapper.MapItemToNew<PressRelease>(item);
        }
    }
}

 Installation

This component is available on NuGet:

https://www.nuget.org/packages/Constellation.Foundation.ModelMapping

Use PackageManager within Visual Studio and add it to the appropriate project:

PM> Install-Package Constellation.Foundation.ModelMapping

This package does not ship with any Sitecore data, but it does have a mandatory configuration file. If you reference this component from a .NET Framework Class Library, you will need to ensure that your website contains the configuration file, or mapping will not work as expected.

The source code for this component is available as part of a larger Visual Studio solution containing all Sitecore 9+ Constellation components.

https://github.com/sitecorerick/constellation-sitecore9

Next Steps