ASP.Net MVC Framework - Create your own IRouteHandler
In my previous post I wrote about how we can create our own IControllerFactory for the ASP.Net MVC Framework; in this post I will show you how we can create our own IRouteHandler.
The RouteHandler in this post will replace the IControllerFactory with my own Controller Factory, and also set a default ControllerFactory and a ViewFactory specified in the web.config. This is something the current preview bits of the MVC Framework can’t.
It’s quite easy to create our own RouteHandler, we only need to implement the IRouteHandler interface and implement the GetHttpHandler method ;)
public class N2MVCRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
N2MVCHandler handler = new N2MVCHandler();
handler.RequestContext = requestContext;
return handler;
}
}
The GetHttpHandler returns an IHttpHandler. I have created my own IHttpHandler (N2MVCHandler). The N2MVCHandler inherits the MvcHandler shipped with the ASP.Net MVC Framework. The reason why I inherit the MvcHandler is because I don’t want to rewrite stuff that isn’t necessarily. In my IHttpHandler I override the ProcessRequest method and added my own code to create a Controller for the current request.
public class N2MVCHandler : MvcHandler
{
protected override void ProcessRequest(IHttpContext httpContext)
{
if (this.RequestContext == null)
throw new InvalidOperationException("No RequestContext");
string controllerName = this.GetRequiredString(this.RequestContext.RouteData, "controller");
IController controller = this.CreateController(controllerName);
ControllerContext controllerContext = new ControllerContext(base.RequestContext, controller);
controller.Execute(controllerContext);
}
private IController CreateController(string controllerName)
{
N2MVCConfigurationHandler config = ConfigurationManager.GetSection("Nsquared2/N2MVCSection") as N2MVCConfigurationHandler;
IN2ControllerFactory controllerFactory = N2ControllerFactoryBuilder.GetControllerFactory(config.ControllerFactory);
IController controller = controllerFactory.CreateController(base.RequestContext, controllerName);
return controller;
}
}
In the ProcessRequest method I also create a Controller for the current request by calling the CreateController method. The CreateController method in the N2MvcHandler instantiates a ControllerFactroy which is specified in the web.config file. When the factory is instantiated I make a call to its CreateController method to create an instance of the Controller.
In this example I have replace the IControllerFactory with my own interface, the reason is that I want to pass the name of the Controller and not the Type. The MvcHandler shipped with the MVC Framework will in the ProcessRequest method try to locate the Controller within the references assemblies and create the Type of the Controller and pass it to the IController.CreateController method. But I think it’s up to the ControllerFactory to look up the Controller. Here is my IControllerFactory interface:
public interface IN2ControllerFactory
{
IController CreateController(RequestContext context, string controllerName);
}
Note: You can still create your own ControllerFactory, but you need to implement my interface instead of IControllerFactory, and you don’t need to make a call to the ControllerBuilder.Current.SetDefaultControllerFactory method in the Application_Start event in Global.asax to specify which ControllerFactory you want to use, instead you can do it in web.config. You will see how to do it later in this post.
I decided to use Spring.Net in this post also to create my Controller within the ControllerFactory.
public class N2ControllerFactory : IN2ControllerFactory
{
public IController CreateController(RequestContext context, string controllerName)
{
IResource input = new FileSystemResource(context.HttpContext.Request.MapPath("objects.xml"));
IObjectFactory factory = new XmlObjectFactory(input);
if (typeof(Controller).IsAssignableFrom(controller.GetType()))
{
N2MVCConfigurationHandler config = ConfigurationManager.GetSection("Nsquared2/N2MVCSection") as N2MVCConfigurationHandler;
((Controller)controller).ViewFactory = N2ViewFactoryBuilder.GetViewFactory(config.ViewFactory);
}
return controller;
}
}
The IViewFactory is used to create a factory which has the responsibility to create a View. Because a Controller don’t need to implement the Controller base class I will in my code use a "code policy". I will check if the created Controller inherits the Controller class, if so I will create a IViewFactory and inject it to the Controller. The IController interface don’t have the ViewFactory property, it’s something we will get from the Controller base class.
If we take a look again at the CreateContoller method in the IHttpHandler (N2MVCHandler), we can see how I get the ControllerFactory from the web.config
private IController CreateController(string controllerName)
{
N2MVCConfigurationHandler config = ConfigurationManager.GetSection("Nsquared2/N2MVCSection") as N2MVCConfigurationHandler;
IN2ControllerFactory controllerFactory = N2ControllerFactoryBuilder.GetControllerFactory(config.ControllerFactory);
IController controller = controllerFactory.CreateController(base.RequestContext, controllerName);
return controller;
}
I use some other helper classes in my code to create an instance of the Controller- and ViewFactory specified in the web.config, the code of the helper methods is not relevant for this post. When the public CTP of the MVC Framework is released, you can drop me an e-mail and I can send you my source code.
Here is the config section in the web.config where a conrollerFactory is specified and also a viewFactory. So we can now easy specify our ControllerFactory and ViewFactory in web.config.
<Nsquared2>
<N2MVCSection
controllerFactory="MvcApplication.Models.N2ControllerFactory, MvcApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
viewFactory="MvcApplication.Models.N2ViewFactory, MvcApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</Nsquared2>
By using the Route objects’ RouteHandler, we can easy change the RouteHandler the MVC Framework should use.
RouteTable.Routes.Add(new Route
{
Url = "[controller]/[action]/[id]",
Defaults = new { action = "Index", id = (string)null },
RouteHandler = typeof(N2MVCRouteHandler)
});
In this post you have seen how we can create our own IRouteHandler, and also replace the ControllerFactory with our own.