Navigation and service panel


Content

Differentiate ViewModels and DomainModels in view renderings using Glass Mapper

By Kevin Brechb├╝hl on 29. August 2014, No comments

In an ASP.net MVC application, DomainModels and ViewModels are widely used. But often it's not clear what these are for and how we should separate them. This blog post shows my architectural point of view about how to differentiate ViewModels from DomainModels, how to use them in theory and how to integrate them into Sitecore view rendering with Glass Mapper.

In Sitecore view renderings we can define a model, which is being resolved by the getModel-pipeline and injected into the Razor view. Obviously this type of model is called a ViewModel. When using Glass Mapper we also have a so called DomainModel, which represents the data from the database.

First of all, it's important to understand what the difference between a ViewModel and a DomainModel is. The DomainModel is used to represent the data from our data source. When using an Object-relational mapping like Glass Mapper, we use this model to define the structure of the Item within Sitecore. If we have an Item with two fields FirstName and LastName, we also have these two properties within our DomainModel. On the other hand, the ViewModel is used for displaying the data in the view (in ASP.net MVC this is the Razor view). Assume, that in the frontend of our Website, we want to display the name of a person as a single string and not distinguish between first- and lastname. Then our ViewModel only has a property Name, which should contain the first- and lastname of the DomainModel, separated by a space. There are different approaches on how to integrate this concept into a MVC application.

Use only one class for both

As this are only classes in the code, you could also create a class containing three properties. Use FirstName and LastName for the ORM and use Name in the view. However in my opinion this is not a good idea. In software architecture you should always care about separation of concerns: What if you need 100 properties in the DomainModel and only 1 in the ViewModel? What if the names of properties within the DomainModel change? This also affects the view. The presentation layer should not depend on the data access layer, and that's why we want to separate these two models.

But of course directly using the DomainModel is the most straight forward, easy way of using the properties in the view. This is also the way how Sitecore view renderings basically work: You can select a model in the view rendering, which is being resolved by the getModel-pipeline. Then a view rendering can have a data source linking to an item (or the Sitecore.Context.Item). Because a view rendering is always within the context of an item, why not simply take the mapped DomainModel as ViewModel? It's very easy to handle this with Glass Mapper. There is also a tutorial available for this.

Completely separate the models

In a puristic view of software architecture, this would be the way to go. But it's not always the best way because you need to have "something" that maps the DomainModel to the ViewModel (i.e. AutoMapper). However this would only be easily possible with controller renderings. Because view renderings don't use their own controller, I would not use this approach for view renderings. Additionally the Page Editor functionality would get lost because we don't have any references to the Sitecore fields.

Having a property for the DomainModel

In a mix of both approaches we'd have a property for the DomainModel within our ViewModel. This actually fits very good to my needs and is easy to implement and use in view renderings. So let's do it.

Some code

Let's take the sample items from a clean Sitecore installation with Glass Mapper installed. You could also install the MVC Sample package to try this out. The DomainModel of the sample item is the following:

[SitecoreType(TemplateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}")]
public class DomainModel
{
    [SitecoreField(FieldName = "Title")]
    public virtual string Title { get; set; }

    [SitecoreField(FieldName = "Text")]
    public virtual string Text { get; set; }
}

In our view we want to say hello to the user, so our ViewModel looks like this:

public class ViewModel
{
    public string Name
    {
        get
        {
            return Sitecore.Context.GetUserName();
        }
    }
}

But we also want to show the title of the current item (which is available in the corresponding DomainModel). To have a solution for all possible ViewModels we create a generic base class with the GlassItem property which stores the DomainModel. Because this base class inherits from Sitecore's RenderingModel, the Initialize() method get's called within the getModel-pipeline while initializing and resolving the model defined in the view rendering. This is the point where we can load the defined DomainModel into our property.

public abstract class ViewModelBase<TValue> : RenderingModel where TValue : class
{
    public virtual TValue GlassItem { get; set; }

    public override void Initialize(Rendering rendering)
    {
        base.Initialize(rendering);
        this.GlassItem = RenderingContext.Current.Rendering.Item.GlassCast<TValue>();
    }
}

Our ViewModel only needs to inherit from this base class and specify the type of the DomainModel, in our case DomainModel (what a good naming, ehm?):

public class ViewModel : ViewModelBase<DomainModel>
{
    public string Name
    {
        get
        {
            return Sitecore.Context.GetUserName();
        }
    }
}

In the view we inherit from GlassView (to support the Page Editor) and then have access to both, our ViewModel and our DomainModel properties:

@inherits Glass.Mapper.Sc.Web.Mvc.GlassView<Website.Models.ViewModel>

<div>
    <h1>Hello @Model.Name</h1>
    <h2>@Editable(m => Model.GlassItem.Title)</h2>
</div>

I think this is a nice compromise, as we have separated the model types, have access to all properties we need and do not have to implement anything special for each ViewModel we have. What do you think? Do you have other opinions and ideas on how to handle ViewModels and DomainModels in your presentation layer? Feedback via comment or Twitter is very much appreciated.

No comments

Add your comment

Your email address will not be published. Required fields are marked *

*