In this tutorial, you will learn how to inject a view model into a master layout view within an Episerver CMS powered website. The job of the master layout is to render the HTML skleleton that is shared between your web pages. In the layout view, you will add the site script references, the pages head section, the body tag, as well as the header and the footer. If you did not implement a master layout within your project, you would need to duplicate the HTML required to render these components within each page view.
The biggest complication with master layouts is the
head section. Within a pages head section, you will need to render specific data about a page. Properties include the title, the description, etc... Due to these properties needing to be in the layout, you will need a way of accessing the current page object within your layout. This poses the problem, how do you inject data into a layout?
The steps that you are required to follow in order to render a page with Episerver CMS is pretty well documented and easy to understand. You create a controller, inherit from
PageController using the page type that you want to associate the controller with as
T. You then create a view model and pass it into a view. As a layout can not be associated with a controller, how do we accomplish the same thing within a layout? In this guide, you will learn all the steps to accomplish this. If you are starting a new Episerver project, this is the tutorial for you 🔥🔥🔥
To follow good practice, we do not want to simply write C# code in our master view. Instead, you should inject a view model into the layout. For this guide, we will be using this view model:
The biggest challenge when building a layout is how and where to populate this view model. We need to somehow populate this object on every page request. To understand how you can do this, let us start by talking through the end-to-end page rendering process. When a site visitor makes a page request, Episerver gets the URL and tries to find a match within the database. Assuming it finds one, the current page is added to the request context. Based on the pages page type, a corresponding controller is called and the data in the request context is converted into an Episerver page type. The controller then calls a view.
Within the view, if a master layout is defined it will be loaded and the content of the pages will be wrapped in the
RenderBody() call. If no master layout is specified in the view, but a default template is specified in
_ViewStart.html file the same process is followed.
We want a way to run the same code on every request before this layout is called in order to populate a view model. We can do this with a
A request filter will allow you to run some custom code before a controller is loaded. By creating a request filter, you can ensure some custom code is run on every page request. The code to create this filter is shown below:
On Line 5,
Controller.ViewData.Model is used to get the currently requested model within the request context. This code is vanilla .NET and not Episerver specific. Before injecting a layout view model, you should check the request is a page request and not a block request. You can do this by checking the request model is of type
PageData If the request is for a block, ignore it 🤔
On Line 7, you can also see that the code is checking if the model is equal to
IPageViewModel is a custom interface that we will create in a minute. Later on, we need to create a base controller that all pages will inherit from. If the current page request inherits from our base controller, we know we need to create a view model as the layout will also be rendered within this request.
Next, let us create the
IPageViewModel interface. This is the type that will glue everything together:
As you can see this interface uses generics. The rule defined on the interface, states that anything passed in as
T needs to inherit from
PageData. The interface also contains a property to store our custom view model.
Base View Model
The next step is to create a base view model. You will need to ensure that every page controller in your project returns a view model that inherits from this base type otherwise the layout view model will not be created:
That covers all the custom code required to start injecting populated view models into your master layout. For completeness, I will also include all the Episerver code to make this happen 💥. Let us say we have a page type defined called
StartPage, you would define this controller:
To associate a view model with this controller, we will create
StartPageViewModel is inheriting from
BaseViewModel ✔️. The last part is creating the master layout. In this example I will call it
On Line 1, the code uses
@model IPageViewModel<BasePage> to type the view. That gives the view access to any properties defined within
BaseViewModel. Job done 💥
You have now learnt about the most frequently used pattern to inject data into a master layout using Episerver CMS. This is not the only pattern, however, it works. When rendering a layout, you should use a view model in order to keep with the clean separation of concerns paradigm that is at the heart of MVC. The secret to making this work is the result filter. A result filter will allow you to run custom code on each request. In its
OnResultExecuting() method you can define and inject a view model in the layout. If you are struggling to get this working in your project, a working example you be found [here] (http://jondjones.com/learn-episerver-cms/episerver-developers-guide/episerver-sample-sites/jondjones-episerver-8-blog-sample-site/). Happy Coding 🤘