LA.NET [EN]

Jul 24

As we’ve seen in the previous post, all “MVC routing requests” are handled by the MvcRouteHandler class which will simply return an instance of the MvcHandler type. The MvcHandler is an IHttpHandler which is responsible for creating other classes that end up handling the current request and processing its response.

This handler doesn’t create an instance of the controller directly as you might think! Instead, it will try to get a reference to an IControllerFactory element, which will be responsible for creating a IController instance (in other words, the MvcHandler creates the controller that will handle the request though a controller builder). If you look at the ProcessRequest method, you’ll see that it uses the static GetControllerFactory method of the ControllerBuilder class for getting a reference to an IControllerFactory:

IControllerFactory factory = ControllerBuilder.GetControllerFactory();

The ControllerBuilder class is interesting and it gives you another extensibility point: you can use its static Current property to get a reference to the current builder instance and then call the SetControllerFactory method to setup the factory that will end up creating the controller that handles the request (as you might expect, if you do this, the GetControllerFactory method will return an instance of that custom factory).

Instead of wasting time writing about how you can customize the factory, I’ll simply point you to Fredrik Normen’s post on that subject (the only thing I’d like to add is that I’ve used this solution in some dummy MVC apps and it is really great when you’re using IOC).

The IControllerFactory interface defines a contract with two methods:

public interface IControllerFactory {
  IController CreateController(RequestContext context,
                                                                    string controllerName);
  void DisposeController(IController controller);
}

As you can see, the factory receives the current RequestContext and the controller name, which is recovered by the MvcHandler during the initial phase of the ProcessRequest method (it uses the GetRequiredString instance method of the RouteData class to get that info). As you might expect,the DisposeController method ends up getting called at the end of the request and you can use it to do some cleanup (if you need to).

If you don’t build your own controller factory,you’ll end up getting a default factory: an instance of the DefaultControllerFactory class.  The first thing this class does is recover the type of the controller that should handle the current request. It first tries to get a list of namespaces defined on a “custom” Namespaces entry available on the DataTokens property of the current route. If it doesn’t find any match, then it tries to search in the namespaces collection of the associated controller builder instance. And finally, if it didn’t find any matches in the previous attempts, it will simply try to look in all the available namespaces.

What this means is that you can now have controllers with the same name, in different namespaces and you can hint the factory about which controller should be instantiated to handle a specific route request (as you’ve seen, this can be done when creating the route or by customizing the associated controller builder). Do notice that if you do this (ie, build several controllers with the same name) you’ll need to define the namespace associated to each route. If you don’t and get multiple controllers, you’ll end up getting an exception.

As you might expect, the DefaultControllerFactory relies heavily on reflection to perform its work. If it had to handle to discover all the controllers during all the calls, you’d really have ppor performance! Instead, it relies on the ControllerTypeCache class to discover and cache all the controller types available on all the assemblies “loaded” by the web app. So, at the end of the day, the ControllerTypeCache does all the hard work of getting the controller types and enforces the convention that controller type names should end up with “Controller”.

After getting the controller from the factory, the handler will call the Execute method and pass it the current context. In the next post we’ll keep following the handling of an MVC request. Keep tuned.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>