If you are familiar with MVC then the concept of abstracting your presentation files from your business logic should be pretty self-explanatory. If you're not sure about this, then I recommend reading up on MVC a bit.
Most people are very familiar with creating an Episerver page, wrapping the result in a view model in the controller and passing it on to the view to use. On a lot of projects I've come across, people may follow this principle but when it comes to the layout file, the head and the footer, then for some people this principle goes out the window.
On all of my projects, I will create a base Layout View Model. The model will contain all the properties needed for the header, footer, breadcrumb etc.. In this guide I'm going to cover how to hook into the MVC pipeline to inject the model for all page requests, and then how to use the View Model in your layout.
The first part of this puzzle is to create a view model, I'm going to use a very basic example:
In a production environment, this model will be huge but this will do to explain the principle. Now we have a global view model, we need to somehow populate it on every page request and attach it into the content. I'll try and talk through the process when someone tries to load a page, the request is sent to Episerver for the page type that matches the request.
Episerver populates the page type with the appropriate data and pushes it into the MVC pipeline. MVC will then look for a controller that matches the request. The controller is defined using the Episerver PageControler class.
When MVC finds the controller, the page is passed into it via an action method argument. Depending on how you structure your project, the page is usually added into a view model and then the view model is returned to the pipeline. Using the standard MVC naming convention, the view will be called (based on the names).
Within the view, the master layout to use will be defined, otherwise MVC will use the default master view defined in the _ViewStart.html file. The problem with this scenario, like Episerver, how do you hook into the pipeline to inject your own object?
In EpiServer's case they want to inject the page object being requested fully populated with data. In our case, we want to populate a layout view model with all the data required to render the header and footer. MVC allows us to do this using Result filters (Or IResultFilters). A 'result filter' allows us to interact the MVC pipeline and run custom logic before and after a view is executed.
In our example, we want to run some code before our Layout is called. Populate a view model and then add it to a ViewBag or similar method to attach an object to the page request. We can then use the model in _Layout.cshtml to make everything type-safe.
Creating The Results Filter
The first line 'Controller.ViewData.Model' is an MVC thing that gets the currently requested model in the MVC pipeline. We will use this model to first, determine if the request is for an Episerver page (if it's for a block preview, for example, ignore it).
The second line checks if the model is of type IPageViewModel. This type is a custom thing that I will create in a minute. At the moment, all you need to know is that in order to get this to work we need to create a base model that all pages will use. If the current model inherits from our base page, then create a new layout view model and add it to the model. If the request is from a page we care about, set the layouts view model on it.
Global Base Page
First, let's create the interface that will glue everything together:
This inherits from PageData as the request will always be an Episerver page. We have a property to store our custom view model, we have a property to store the current page object. The next step is to create a base View Model. In order to get this to work, every page will now need to return a view model that inherits from this:
That's it really for the custom code. The rest is standard Episerver stuff. Lets say we have a page type defined called 'StartPage'. In order to render the 'StartPage' we would have a controller defined as so:
The code for 'StartPageViewModel will look like this:
The last part is updating _Layout.cshtml view to include our View Model:
That's it! You now have all the code you need to get this up and running. This example is very basic. The problem with it is that the Header string will never be populated.
When you start building your Episerver websites, you will either create a page or block to store your header and footer data, or you will include the fields on the homepage in separate tabs. In your view model, you will then call the homepage, for example, read in and set all the properties.
Let's recap. Having a View Model for our layout is a good thing to keep with the abstraction approach that is at the heart of MVC. In order to implement this, we need to hook into the MVC pipeline before our views are called and inject.
We do this using a Result Filter. The way the new world will work is that in every page controller, we now have to return a view model that inherits from a custom interface that we define.
The interface provides the mechanism to store the new layout view model. In the results filter, we checked if the current page request/model inherits from our custom interface. If it does, we populate the layout view model data and attach it to the request. If it doesn't, we ignore it and let the request load as usual.
Finally, in within the view, define the type. This will give enable IntelliSense for the mode and give you type-safety.
Trying to get lots of code in a blog post up and running can be a pain. If you want to download a working example you can get full source code to my sample site here, [http://jondjones.com/learn-episerver-cms/episerver-developers-guide/episerver-sample-sites/jondjones-episerver-8-blog-sample-site/] (http://jondjones.com/learn-episerver-cms/episerver-developers-guide/episerver-sample-sites/jondjones-episerver-8-blog-sample-site/)