08 Sep 2010

Simple REST API Versioning Using MEF and MVC

8 Comments Uncategorized

I know that is a whole host of acronyms in the title, so let me explain.  Recently it came to my attention at my day job that I was going to have to support two versions of our API simultaneously.  This information came as no surprise to me, but unfortunately it wasn’t something I originally planned for when carefully laying out the URL patterns for the REST API.

Since I was going to have to yank the current code apart to support the new API in parallel with the previous API, I decided to do things right and put a wish list in place for what I wanted to accomplish with the next version of the API:

  1. Ability to support /vN/ (ex. /v1/ and /v2/) in the URL so that the URL looks like http://mysite/v1/api/method
  2. Ability to deploy versions of API in separate DLL’s, so that the URL is versioned similar to the libraries.

As I was searching for a non-hacky way to accomplish this I stumbled across using MEF for creating a MEF based MVC Controller Factory.  This was a great find because it provided me everything I was looking for.  It allowed me to add meta data to each controller, so that I could specify the version that the controller was (i.e. “v1” or “v2” etc.).

To get started the first thing I needed to do was setup the MEF container.  On the web it is a little more complicated, because of the stateless nature of a web application.  So I created a MefHttpApplication base to replace the standard HttpApplication in the Global.asax file.  Here is how it should look:

public class MvcApplication : MefHttpApplication

Next we need to change the default route to support versioning:

routes.MapRoute(
    "Default",
    "{version}/{controller}/{action}",
    new { version = "v1" }
);

After that is completed the next step is to actually register our new Controller Factory with MVC.  This is a very important step because it is the glue between MVC and MEF, and it is what brings the two frameworks together.

public void RegisterControllerFactory(ControllerBuilder controllerBuilder)
{
    controllerBuilder.SetControllerFactory(new MefControllerFactory(ContainerManager));
}

protected override void Application_Start()
{
    base.Application_Start();

    RegisterControllerFactory(ControllerBuilder.Current);
}

Before we go on to create our MefControllerFactory, it is probably best to show how the meta-data attributes for MEF are applied to the controllers, it will make understanding how the MefControllerFactory works easier.  I am not going to go in to much detail, because there are much more in-depth and better explanations than I can give on how these work, I am only going to tell you the code that I am showing you does work:

[Export(typeof(IController))]
[ExportMetadata(Constants.MetaControllerName, "Billing")]
[ExportMetadata(Constants.MetaApiVersion, "v1")]
[ExportMetadata(Constants.MetaScopeMode, WebScopeMode.Request)]
public class BillingController : Controller

The next thing we need to create is the MefControllerFactory.

I am just going to post the parts below that I want to talk about and that are relevant to this blog post, but I have posted the full file online for your viewing pleasure.

With the MefControllerFactory we want to find the controller out of the MEF container that both matches the version and the controller name that is being requested as part of the route.  To do this we can use LINQ:

controllers = controllers
    .Where(exp =>
        exp.Metadata.ContainsKey(Constants.MetaControllerName)
        && String.Equals(exp.Metadata[Constants.MetaControllerName].ToString(), controllerName, StringComparison.InvariantCultureIgnoreCase))
    .Where(exp =>
        exp.Metadata.ContainsKey(Constants.MetaControllerName)
        && String.Equals(exp.Metadata[Constants.MetaApiVersion].ToString(), version, StringComparison.InvariantCultureIgnoreCase));

The above LINQ query queries for all controllers in the MEF container that have both the same controller name and same API version as was requested by the route. The important parts to notice about the above query is the names Constants.MetaControllerName and Constants.MetaApiVersion they are the same constants that are used in the above ExportMetadata attributes on the controller.

The last part to getting this working is merely a preference of mine.  But when I create a versioned URL schema like this I like to have separate projects for each version, so I break out the Controller classes in to their own project, so that I have a library of just controllers.  I do this so that when I want to create another version of the API say going from v1 to v2 or v2 to v3, I just need to take a copy of my entire controller project and update the versions and start working from that point moving forward.

Hope this helps somebody, because versioning your web API is a complex process, because if you don’t want to be a totally jerk to your users you have to support both interfaces for a period of time to give the users a chance to move from the current version to the next.  My goal with the above code was to make supporting both versions easy.

27 Jul 2010

ASP.NET MVC 3 Preview 1 Released

No Comments Uncategorized

The title says it all, so go get your copy today and check out all the new features.  You can download it here.

New features include:

  • Razor View Engine
  • Dynamic View and ViewModel Properties
  • “Add View” Dialog Box Supports Multiple View Engines
  • Service Location and Dependency Injection Support
  • Global Filters
  • New JsonValueProviderFactory Class
  • Support for .NET Framework 4 Validation Attributes and IValidatableObject
  • New IClientValidatable Interface
  • Support for >NET Framework 4 Metadata Attributes
  • New IMetadataAware Interface
  • New Action Result Types (HttpNotFoundResultAction and HttpStatusCodeResultAction)
  • Permanent Redirect Support in the controller (RedirectPermanent, RedirectToRoutePermanent, and RedirectToActionPermanent)

Looks like this is going to be a very worth while upgrade, and a special thanks should be given to Phil and team for making ASP.NET MVC everything that ASP.NET WebForms isn’t.

11 May 2009

Creating Your First MVC ViewEngine

13 Comments Uncategorized

A question that I have been hearing a lot lately is:

How do I change the view location in MVC?

But what they really mean to say is:

How do I create a new ViewEngine that uses the view locations of my choosing?

It is actually very simple to do, and once you see it, I think you will agree with my assessment.  The first thing we are going to do to create our custom ViewEngine, is define the paths that we want to use for our master pages, view pages, and shared pages.  I have taken the liberty to define the following paths, you can customize them however you wish:

  • Master Pages:
    ~/Templates
    it use to be ~/Views/Shared or the controllers view
  • View Pages:
    ~/Views
  • Shared Pages:
    ~/Common
    it use to be ~/Views/Shared

The next thing we need to do is create a new class for our ViewEngine, for this example we are going to call it SimpleViewEngine.

public class SimpleViewEngine : VirtualPathProviderViewEngine
{
}

As you might have noticed from above our SimpleViewEngine inherits from VirtualPathProviderViewEngine, this is the root ViewEngine that uses the VirtualPathProvider (VPP). The VPP provides a way for web applications to read files off the file system in their local web application, so it is perfect for what we are doing. If you don’t want a file system based ViewEngine, and maybe want a ViewEngine based from the database, you can use the IViewEngine interface to create your own custom ViewEngine that fits your needs. (MVC is very flexible, by design)

The next thing we need to do is code our paths in to our SimpleViewEngine. We will do this in the constructor, so that they only have to be initialized once for the entire life span of our SimpleViewEngine.

public SimpleViewEngine () 
{
	/* {0} = view name or master page name
	 * {1} = controller name
	 */

	// create our master page location
	MasterLocationFormats = new[] {
		"~/Templates/{0}.master"
	};

	// create our views and common shared locations
	ViewLocationFormats = new[] {
		"~/Views/{1}/{0}.aspx",
		"~/Common/{0}.aspx",
	};

	// create our partial views and common shared locations
	PartialViewLocationFormats = new[] {
		"~/Views/{1}/{0}.ascx",
		"~/Common/{0}.ascx"
	};
}

As you can see the format is pretty straight forward. We create a string[] array with the paths of where our master pages, views, and common views are located. The only thing that we need to do is set place holders in our path so the the VirtualPathProviderViewEngine can replace the master name, view name, and controller name to construct our appropriate path.

  • {0}: is the view name or master page name.
  • {1}: is the controller name.

After we have done the hard part, which honestly wasn’t that hard, of creating the constructor with the paths, we just need to return the view objects from the constructed partial paths. Since we are using the standard ASP.NET Web Form (ASPX/ASCX) rendering engine. We are able to leverage the work already done by the MVC team and just return a new instance of the WebFormView object.

protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
	return new WebFormView(partialPath, null);
}

protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
	return new WebFormView(viewPath, masterPath);
}

Nothing really earth shattering here, just simply filling out the constructor with the proper parameters from our method, and then returning the newly created view. If you wanted to create a view based out of the database, or off your own syntax (meaning not ASP.NET syntax) then you would have to create your own view based off of the IView interface. But for this example we are only concerned with changing where our views are located.

There is one more thing that we need to do, and that is register our new SimpleViewEngine for use in the framework. The registration of view engines is done in the Global.asax, similar to the same way we register new routes.

public static void RegisterViewEngines(ViewEngineCollection viewEngines)
{
	viewEngines.Clear();
	viewEngines.Add(new SimpleViewEngine());
}

public static void RegisterRoutes(RouteCollection routes) { ... }

protected void Application_Start()
{
	RegisterRoutes(RouteTable.Routes);
	RegisterViewEngines(ViewEngines.Engines);
}

So we are now done. You have created a new view engines, defined your own routes, and registered this view engine with the MVC framework. Some other types of paths you may want to consider trying for your applications, using a custom ViewEngine, are special folders for your mobile or Facebook versions of your website.

  • Mobile: ~/Views/{1}/Mobile/{0}.aspx
  • Facebook: ~/Views/{1}/Facebook/{0}.aspx

I told you it was simple and straight forward, and I hope you agree that the MVC team has done an awesome job at providing a very flexible framework for us to tweak and customize it so it fits our applications.