What Should The MVC ViewModel Be Used For in Episerver ?

We recently had a discussion in the office about the point of using a view model in Episerver, what should go in it and why it’s needed.  A lot of the team had very conflicting views, so I thought I’d share my views.

For a quick MVC overview recap, in MVC you have a View which contains your html (css, js, etc..) in a .cshtml file, a model (a page type or block type definition) and a controller that defines how the model will be passed to the view, who can access it, how it should be cached etc… and a ViewModel.

What is the point of the ViewModel?

One definition of what the ViewModel should be used for, is a filter between the properties defined in the pages and blocks properties and what is exposed to the front-end view.  For Episerver that means never exposing the Page Type of Block Type definition directly but adding properties for the things that will be displayed.

In my opinion, this just seems like a lot of boiler plate code to write, especially if you don’t have anything security wise to warrant all the effort.  So if we’re not going to use this definition of what a view model is… what are we?

Episerver ViewModel

When I usually design a site, I’ll create a base viewmodel for pages and blocks.  An example of what that base view model class would look like is shown below:

{
public class PageViewModel<T> : IPageViewModel<T> where T : SitePageData
{
public PageViewModel(T currentPage)
{
this.CurrentPage = currentPage;
}
public T CurrentPage { get; private set; }
}

The ViewModel code would look like this:

public class LandingViewModel : PageViewModel<LandingPage>
{
public LandingViewModel(LandingPage currentPage)
: base(currentPage)
{
}
}

The code to return the ViewModel to a view would look like this:

return View("Index", new LandingViewModel(currentPage));

Following this approach, you have the underlining page and block properties exposed to your view.  So apart from forwarding on the page or block property what should go in there?

Friendly Url/Link Resolving

In a lot of pages/blocks we need to link to other internal pages within the website, however, when we render a pages LinkUrl property it renders out the internal Url which is useless for your SEO. The View Model is the perfect place to add a link resolver to display the friendly Url.

public string ImageUrl
{
get
{
return this.CurrentBlock.ImageUrl.IfNotDefault(this.LinkResolver.ResolveUrl);
}
}

I haven’t included the code for the link resolver in this article, but if you want to get yourself a copy have a look at my Dependencies article.

CSS Logic

As we can have multiple views for a block, we want to keep all logic out of the view to stick to the DRY principle, so the next best place to keep it is within the ViewModel.  When you start integrating your HTML, you will undoubtably hit situations where you need to change the class based on a certain criteria, for example you may have an editor option to Hide a heading on a block:

public string HideHeadingClass
{
get
{
return CurrentBlock.DisplayBox ? "none" : string.Empty;
}
}

This snippet will render a “none” class if the user has enabled it, otherwise nothing will be displayed and the heading will display.  If you have multiple views for a control this will reduce duplicate code in each view.  Doing this also allows you to unit test that the right class is displayed in the right situation.

Concatenating Multiple Elements Into A Single Property

Let’s say you have a block with a Title, First Name and Surname property. In your ViewModel you can create a FullName method to save you having the concatenation code in your view.

public string FullName
{
get
{
return string.Format("{0} {1} {2}", CurrentBloct.Title, CurrentBlock.FirstName, CurrentBlock.Surname);
}
}

Image Alt Tags

To have good SEO you need to have Alt tags but sometimes an editor may not add one.  In the Viewmodel you enforce, the Alt tag has a value.

public string ImageAlt
{
get
{
return string.IsNullOrEmpty(CurrentBlock.ImageAlt) ? CurrentBlock.Heading : CurrentBlock.ImageAlt;
}
}

Rendering Custom HTML Elements

You may also want to render your own custom Html tag.  The following tag will render out a different heading tag like

based on a selection factory defined in the block, for example:

public MvcHtmlString Heading
{
get
{
var tag = CurrentBlock.HeadingSize;
return new MvcHtmlString(string.Format("<{0}>{1}</{0}>", tag, CurrentBlock.HeadingText));
}
}

Filtering Content Area Contents

When you have a block like a carousel, you will likely have a number of child blocks, usually within a content area defined on the parent.  You can use the View Model to iterate through those items and return them in list or even DTO/Poco to make the rendering code easier.

public IList<CarouselSlideBlockViewModel> Slides
{
get
{
return this.slides ?? (this.slides = this.CurrentBlock.Slides
.GetContentsOfType<CarouselSlideBlock>(this.ContentRepository)
.Select(x => new CarouselSlideBlockViewModel(x, this.BaseDependencies))
.ToReadOnlyList());
}
}

Conclusion

By now I’m hoping you’re starting to see the point of the View Model.  It’s the place to keep code that isn’t part of a page or block type definition and having to add any sort of logic within the view.  Following this approach means you should keep your Episerver page definitions free of code and your views free of code, maintaining a good layer between presentation and business logic.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

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