In a previous post I described my first attempt at working with EPiServer and MVC along with Page Type Builder. In that solution all controllers inherited from a base class which had an instance of a class called CurrentPageResolver. Each controller action method received the URL segment (or slug) for a page and then used the CurrentPageResolver to retrieve the corresponding PageData object.
This method has a serious flaw in that it makes the controller do more than it should, and what’s even worse, it renders the actions almost impossible to unit test as the CurrentPageResolver in turn will fetch the PageData object from DataFactory and in the end the database.
A much cleaner solution, which makes the controllers highly testable, is to let each action method have a currentPage parameter of type PageData (or in my case BasePageData). This is easily done by creating a custom model binder.
The first thing we should do, compared to the solution I described in the previous post, is to modify the controllers. Below is an example, my ArticleController. It no longer inherits from ControllerBase (which I removed from the project) and the actions have a currentPage parameter.
public class ArticleController : Controller { public ActionResult Index(BasePageData currentPage) { return View(currentPage); } public ActionResult Edit(BasePageData currentPage) { return View(currentPage); } }
Secondly, we should create a custom model binder by creating a new class that implements IModelBinder.
public class PageDataModelBinder : IModelBinder { public PageDataModelBinder() { CurrentPageResolver = new CurrentPageResolver(); } private CurrentPageResolver CurrentPageResolver { get; set; } public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { string slug = (string) controllerContext.RouteData.Values["slug"]; return CurrentPageResolver.GetCurrentPage(slug); } }
When asked for a model object our model binder retrieves the slug part of the route and asks an instance of CurrentPageResolver for the corresponding PageData object.
The last step is to register our model binder as responsible for delivering objects of type BasePageData (which is the base type for all of my PageData objects). This is easily done in global.asax.
protected void Application_Start(Object sender, EventArgs e) { ModelBinders.Binders.Add(typeof(BasePageData), new PageDataModelBinder()); }
Source code
I’ve zipped the relevant parts of my project and put them up for download here.
PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.
Similar articles
- A first stab at EPiServer CMS with ASP.NET MVC and Page Type Builder
- EPiServer and MVC – What is the view model?
- EPiMVC – A framework for using EPiServer CMS with ASP.NET MVC
- EPiAbstractions.Opinionated – A wrapper for EPiServer CMS and Page Type Builder
- Custom routing for EPiServer content
- Introducing EPiMVP – A Framework for using Web Forms MVP with EPiServer CMS
- Sweet EPiServer Templating with TypedPageList
- Automatically organize EPiServer pages - Part 2
My book
Want a structured way to learn EPiServer 7 development? Check out my book on Leanpub!
Comments
comments powered by Disqus