EPiServer  /  CMS May 10, 2010

EPiMVC – A framework for using EPiServer CMS with ASP.NET MVC

I’m proud to announce a new open source project named EPiMVC which is hosted on CodePlex. My ambition with EPiMVC is to create a framework for building websites with EPiServer CMS and ASP.NET MVC, addressing problems such as routing, URL rewriting, access filtering and rendering properties. Today I’m introducing a first preview of the framework which primarily focuses on routing and URL rewriting.

Background

Since ASP.NET MVC 1.0 was released there has been a few attempts to use it with EPiServer CMS, both by me and by others. There is also at least two sites that have gone live using one of those approaches and this is one of them. However all approaches that I’ve seen so far has been limited in one way or another. Mine didn’t support hierarchical URLs for instance, and Fabio’s didn’t support multiple actions (although you could define specific routes for that). Also, all of our previous attempts has also been limited to addressing the problem with creating and handling URLs. That’s natural since it’s the first and biggest problem that we run into when we try to use EPiServer with MVC. But it’s far from the only one.

With that in mind my stance towards using MVC when building EPiServer sites has been that it’s not worth the hassle for typical EPiServer sites. It’s however a very good idea if you are building a site where the CMS is playing a very small part, such as for a community. But for your typical, content heavy site I’ve been favoring sticking with Web Forms (preferably using the MVP pattern) for the time being until EPiServer adds official support for MVC. I’m also quite confident that we’ll see that happening pretty soon.

A couple of weeks ago Emil suggested that we would do a workshop about using EPiServer with MVC at Valtech and I found myself arguing against it due to my experiences from previous attempts. My arguments we’re primarily that handling URL’s had proven to be so problematic in the past and that it would probably take a very complex solution to handle that. And even if we did manage to solve that we would still loose so many built in features that are tightly integrated with Web Forms that it wouldn’t be worth it.

We left the discussion without either of us having been really convinced. But like so many times before (he’s annoyingly often right) I started thinking about Emil’s and my own arguments and mine started to sound more and more hollow and Emil’s more and more challenging. And since I love a challenge, meet EPiMVC :-)

The problems we face when using EPiServer with MVC

When we try to use EPiServer with MVC we a number of problems. There might be others, but so far I’ve identified five.

Handling URLs

EPiServer has it’s Friendly URL system which gives the illusion of each page having a URL based on it’s place in the content hierarchy, such as /en/news/2010/sales-are-improving/. ASP.NET MVC on the other hand has URL’s that describes behavior, such as /article/view/sales-are-improving/. If we need to pass other information using the URL we usually do this with a query string parameter with EPiSever, such as /en/news/2010/sales-are-improving/?viewcomments=1 while with MVC we would change the action part of the URL, rendering something like /article/viewwithcomments/sales-are-improving/.

I think the hierarchical URL structure is very good for content heavy sites which is what EPiServer CMS is usually used for. But if we find a way to handle those types of URL’s while using MVC we need a way to include other information such as other actions than the default and other parameters without using query string parameters. And on top of that we need to be able to use both MVC and Web Forms at the same time, so anything we do with EPiServers URL rewriting has to be context aware, only interfering with the standard rewriting functionality for page that are supposed to be handled by an MVC controller.

Must have rendering functionality

While many of use only use the Property web control that is shipped with EPiServer sporadically it is almost a must when it comes to rendering XForms and to a lesser degree when rendering XHTML properties with dynamic content in them. While I haven’t used XForms much myself it’s my understanding that it’s quite widely used so being able to use XForms is important. Unfortunately the current rendering functionality in EPiServer is very tightly integrated with Web Forms so being able to render properties like XForms is definitely a challenge.

On page edit

When we use ASPX pages that inherit from TemplatePage to render EPiServer pages we gain the ability to edit properties that are rendered using the Property web control directly in view mode, a concept called Direct On Page Edit, or DOPE. We also get the right click menu. From what I’ve seen the Direct On Page Edit isn’t very widely used, but the right click menu is. Naturally we loose this functionality if we use MVC.

Rapid development components

EPiServer CMS ships with a set of base classes for pages and user controls that helps us with common and easily forgotten tasks such as verifying access rights and publish status for pages. It also comes with a collection of web controls, such as MenuList, NewsList, Calendar, PageList etc. Using these web controls we can very quickly build commonly used features. While we can live without these components it would definitely be valuable to have some of this functionality out of the box when we build a site with MVC as well.

Templates

It’s a common practice for many to start a new EPiServer project by installing the basic template set shipped with EPiServer, the Public Templates. By doing so we gain basic functionality that we can build upon and quite easily modify to suite our needs. Clearly it would be good with some basic set of templates for an EPiServer site built with MVC. It could however be even less feature rich than the Public Templates.

Solutions – Now and future

Handling URLs is what I’ve been focusing on so far. While there are a few things left to do I think the current solution shows a lot of promise. It mixes EPiServers hierarchical URL structure with MVC’s functional in a good way and it’s possible to use it along side Web Forms. That is you can have some page types rendered by MVC and some by Web Forms should you want to. I have also tried to make it easy to work with, using a set of default conventions, while still being fully configurable. There’s so much more to say on this subject that I’ll have to do it in a separate post.  

I’m quite confident that we can find a way to render dynamic content without the Property control. XForms on the other hand might prove more difficult. The current release ships with a solution, almost exclusively copied from this great set of blog posts by Hugo Bonacci, for rendering Web Forms controls inside a MVC view. So far I’ve been able to use this approach to render a XForm but I’ve been able to make it handle postbacks correctly. This is definitely a priority for future investigation and development. Worst case scenario we’ll have to look at rendering XForms in an IFrame (god I hope not!).

As for editing features in view mode I’d say that the right click menu, or something similar to it is doable. It’s not something that I’ve looked into yet however and it doesn’t feel like it needs a very high priority. Direct On Page Edit is nothing I have any plans at all to support with EPiMVC. Contributions are much welcomed though :-)

The current release already ships with a base class for controllers and I plan to extend that with some basic security and publication state checks. I would also like to create some HtmlHelper extensions or similar to mimic some of the often used features of the web controls shipped with EPiServer.

Unfortunately the current release doesn’t ship with any templates and I don’t foresee that changing in the immediate future as they are dependent on the features described above. But hopefully, and perhaps with some help, it should definitely be possible to get there in a few weeks or months.

Building a site with EPiServer CMS, ASP.NET MVC and EPiMVC

Let’s look at how to use EPiMVC! We begin by setting up a project.

Setting up the project

  1. Create a new EPiServer CMS 6 site with the Public Templates or start with an existing site.
  2. Download EPiMVC and add a reference to EPiMVC.dll. Optionally also add a reference to EPiMVC.WebForms.dll if you want to use web controls. You will also need to download and reference Page Type Builder. Also, when doing so, remember to copy Castle.Core.dll and Castle.DynamicProxy2.dll (shipped with Page Type Builder) to your bin folder.
  3. Add two folders to your project, Views and Controllers.
  4. Open up episerver.config and change URL rewrite provider to EPiMVC.UrlRewriting.MvcUrlRewriteProvider. Once you’re done your urlRewrite node in episerver.config should look something like this:
    <urlRewrite defaultProvider="MvcUrlRewriteProvider">
    <providers>
        <add name="MvcUrlRewriteProvider" 
        description="EPiMVC URL rewriter" 
        type="EPiMVC.UrlRewriting.MvcUrlRewriteProvider, EPiMVC" />
    </providers>
    </urlRewrite>
  5. In the Application_Start method in global.asax add an instance of EPiServerRoute to RouteTable.Routes. Once you're done the method should look something like this:
    protected void Application_Start(Object sender, EventArgs e)
    {
        RouteTable.Routes.Add(new EPiServerRoute());
    }
  6. Optional: Open the site’s project file in a text editor and add {603c0e0b-db56-11dc-be95-000d561079b0}; as a project guid to let Visual Studio know that the project is now a MVC project. More on this can be found here, search for “Visual Studio Integration”.

Creating a page type

Once the project set up we create a page type, Article, for our first page that will be rendered with MVC. We do this using Page Type Builder. If you aren’t familiar with how Page Type Builder works I recommend my tutorial on how to use it.

There’s one thing extra that we need to do when we create the page type. We need to add a MvcPage attribute to it. EPiMVC’s URL rewriter and the EPiServerRoute class needs that as they need to know which requests it should handle and which it shouldn’t so that they wont tamper with request for pages that should be handled by Web Forms pages.

Anyhow, let’s add a page type named Article with a single property, MainBody.

[PageType]
[MvcPage]
public class Article : TypedPageData
{
    [PageTypeProperty]
    public virtual string MainBody { get; set; }
}

Creating a controller

Next up we need to create a controller that will handle requests for pages of the Article page type. To do that right click on the Controllers folder in your project and choose Add –> Controller. Name the controller ArticleController. I’d go into more details about the routing in another blog post but in case you are wondering EPiMVC has a default convention to map pages of type A to controllers named AController. This convention is fully customizable and you can also change the controller mapping for individual page types by using a DefaultController attribute.

Once Visual Studio has added the controller it will probably look something like this:

public class ArticleController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

Visual Studio adds an Action for us named Index. This suites us well as that is the default action name that EPiMVC will map requests to if the URL doesn’t contain an action. You can configure a different default action name, either for all request or for a single page type, more on that in a coming post.

If you change it’s inheritance from Controller to EPiServerControllerBase<Article> it will get a CurrentPage property of type Article. Do that and pass it to the view.

public class ArticleController : EPiServerControllerBase<Article>
{
    public ActionResult Index()
    {
        return View(CurrentPage);
    }
}

Creating a view

Last but not least we need to create a view. Right click on the call to View() in the Index method in the controller and then choose Add View from the context menu. Create a strongly typed view with your page type class as the “View data class”. You can now easily display the current page’s PageName and MainBody property as the current page is the view’s Model property.

<%@ Page Title="" Language="C#" 
Inherits="System.Web.Mvc.ViewPage<EPiServer.PageTypes.Article>" %>
<h1><%= Model.PageName %></h1>
<%= Model.MainBody %>

That’s it! Try it out by adding a page of type Article anywhere in the structure of your site.

Specifying actions and other parameters

You can specify a different action than the default by appending the action name to the end of a page’s URL. EPiMVC will also handle extra parameters. As default they will be added to a list of strings which you can access in a controller using ControllerContext.RouteData.Values["parameters"]. However, you can also add a RouteEnding attribute to your page type specifying how the should be mapped. I’ll come back to this subject later :)

Linking to pages

EPiMVC ships with extension methods for the HtmlHelper (the PageLink method) and UrlHelper (the PageUrl method) classes for linking to EPiServer pages. This is yet another subject I’ll have to cover in greater detail later, but here’s a few usage examples:

<%@ Import Namespace="EPiMVC" %>
<%@ Import Namespace="EPiMVC.Html" %>
<%@ Import Namespace="EPiServer.Core" %>
<%= Html.PageLink("Link", Model.SomeOtherPage.PageLink)%>
<%= Html.PageLink("Link with Action and parameters.", 
    "comment", Model.SomeOtherPage.PageLink, new {test = 123})%>
<%= Html.PageLink("Link to the start page", 
    "Index", PageReference.StartPage) %>
<%= Url.PageUrl("actionName", Model.SomeOtherPage.PageLink) %>

Let me know what you think!

There is still A LOT of work to do, the code is far from perfect and some of it is still experimental but I think it shows promise. I would love it if you try it and let me know what you think! Also, feel free to grab the source code and play with it. Hopefully the tests can provide some guidance to what it does :-)

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.

Joel Abrahamsson

Joel Abrahamsson

I'm a passionate web developer and systems architect living in Stockholm, Sweden. I work as CTO for a large media site and enjoy developing with all technologies, especially .NET, Node.js, and ElasticSearch. Read more

Comments

comments powered by Disqus

My book

Want a structured way to learn EPiServer 7 development? Check out my book on Leanpub!

More about EPiServer CMS