EPiServer and MVC – Retrieving current page using a custom model binder

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.

Add a comment

Allowed tags: <b>, <em>, <quote cite="">, <code>, <c-sharp-code>, <css-code>, <sql-code>, <xml-code>, <javascript-code>. If you want to display code examples, please remember to write &lt; for < and &gt; for >.

Follow me on Twitter

  1. Blogged: Learning Scala part eight – Scala’s type hierarchy and object equality http://bit.ly/doyszt 1 days ago
  2. @andreakn in markup or code behind? For the latter you can use the getpropertyname extension method 1 days ago
  3. @andreakn No, but there are plans to support the "built-in" props for subscriptions etc somehow 2 days ago
follow me

Latest comments

  1. Svante wrote "Hi, nice catch! However, as you state, you took the easy ..." on Something to beware of when using EPiAbstractions and an IoC container
  2. kad1r, asp.net, c# wrote "It works. Thank you." on Twitter style paging with ASP.NET MVC and jQuery
  3. Pandiya Chendur wrote "Absolutely wonderful article.. Just loved it..." on Twitter style paging with ASP.NET MVC and jQuery

About this site

This blog is built with EPiServer Community, EPiServer CMS, ASP.NET MVC and a bunch of other great products. The source code is available for download at the projects page, where you also can read more about this site and my other projects.

read more