An often discussed topic is how to set up a project's view models, content types and layout.

Most projects usually end up with one of the three patterns described way back in Steve Michelotti's ASP.NET MVC View Model Patterns.

In that post I took a liking to the ViewModelBuilder approach and decided to try it out for an EPiServer CMS site.

View model structure

There are no type parameters and nothing is going on in any constructor. If you feel like it you can keep them clean of any CMS content type coupling as well which makes it easier to setup for example Commmerce products in the same layout but with a different builder class. Properties removed for brevity.

public class LayoutViewModel
{
	public string Title { get; set; }
}
	
public class StandardPageViewModel : LayoutViewModel
{
	public string PublishedSince { get; set; }

	// If CurrentPage makes your life easier you put it here
	public StandardPage CurrentPage { get; set; }
}

The builder class

This one looks great to me. It does all the work and fetching and makes it possible for me to choose which work to do for the specific controller and view. It takes CurrentPage only to work with it and doesn't set it on some property by itself.

public class LayoutViewModelBuilder<TViewModel, TPageType>
        where TViewModel : LayoutViewModel, new()
        where TPageType : SitePageData
{
	private readonly TPageType currentPage;

	private readonly TViewModel vm;

	public LayoutViewModelBuilder(TPageType currentPage)
	{
		this.currentPage = currentPage;
		this.vm = new TViewModel();
	}

	public LayoutViewModelBuilder<TViewModel, TPageType> WithMeta()
	{
		this.vm.Title = SomeLogicSomewhere(this.currentPage);
		return this;
	}

	public LayoutViewModelBuilder<TViewModel, TPageType> WithBreadcrumbs()
	{
		// Fetch data for breadcrumbs and set props needed by breadcrumbs display
		this.vm.BreadcrumbList = SomeLogicSomewhere(this.currentPage); 
		return this;
	}

	public LayoutViewModelBuilder<TViewModel, TPageType> WithSubNavigation()
	{
		// Call repos and setup sub navigation
		this.vm.SubNavigationList = SomeLogicSomewhere(this.currentPage);
		return this;
	}

	public TViewModel Build()
	{
		return this.vm;
	}
}

The controller and view

If you're in a controller where it's view don't need something you just skip that WithX() call.

[SessionState(SessionStateBehavior.Disabled)]
public class StandardPageController : PageController<StandardPage>
{
	public ActionResult Index(StandardPage currentPage)
	{
		StandardPageViewModel vm =
                   new LayoutViewModelBuilder<StandardPageViewModel,
                     StandardPage>(currentPage)
			.WithMeta()
			.WithBreadcrumbs()
			.WithSubNavigation()
			.Build();

		vm.PublishedSince = currentPage.StartPublish.ToTimeAgo();
		vm.CurrentPage = currentPage;	

		return this.View(vm);
	}         
}

The layout file of course uses the LayoutViewModel while the StandardPage view uses StandardPageViewModel.

@model LayoutViewModel
<!DOCTYPE HTML>
<html lang="sv" class="site no-js">
<head>
	<meta charset="utf-8" />
	<title>@Model.Title</title>

Added Friday 30 October 2015 09:32 — Tags for this page: Episerver, ASP.NET, MVC

Comments

  1. Jonas Bergqvist Friday 30 October 2015 12:49

    Very much liked the fluent building. Will try it out

  2. Fredrik Haglund Sunday 1 November 2015 19:14

    I like this pattern. Easier to explain than the current one we teach in Developers Fundamentals. Will try it out.

  3. Marija Jemuovic Tuesday 3 November 2015 10:07

    Ql, can't wait to try it out :)

Add Your Comment