In this guest post, Mark Watts – an Engineering Lead with Tribal’s Software Architecture team – offers some tips based on his recent work with Microsoft’s MVC 3 framework…
I am a big fan of dependency injection and inversion of control (IOC), and so was pleased when I started looking at MVC 3 to find that it uses IOC extensively and provides you with hooks so that you can provide custom implementations of core aspects of the application and request life-cycles.
If we imagine we have a very basic MVC application which allows us to add some data into some backing store via a simple Razor view then the submission request life-cycle may look like:
- User fills in details and clicks “submit”.
- MVC creates the appropriate controller class.
- MVC creates the appropriate model classes.
- MVC populates the models with request data and invokes the appropriate method of the controller class.
- MVC handles the returned ActionResult.
This post describes how to configure your MVC application such that your controllers and models created in steps 2 and 3 respectively are instantiated using an IOC container of your choice (I will be using Castle Windsor). This allows you to write controllers and models which are loosely coupled and easily unit testable.
IDependencyResolver
The IDependencyResolver is the key to IOC in MVC and is used by the framework to resolve dependencies internally, and is also available through the application via DependencyResolver.Current. You can provide your own implementation of the interface by calling DependencyResolver.SetResolver(yourDependencyResolver).
Below is a snippet from a dependency resolver which uses Castle Windsor to do the heavy lifting:
There are two things worth noting here. The first is that I have had to alias the System.Web.Mvc namespace to MVC as Windsor also defines an interface called IDependencyResolver. The second, and more important, thing to note is that if a component is not registered I am calling RegisterAndResolveto try and register the type and then resolve an instance of it at request time.
I said previously that MVC uses the dependency resolver to resolve its internal dependencies, and this is why it is useful to try and do this request time registration. Every time MVC creates a controller or a view it will try and use the dependency resolver – this request time registration allows us to avoid having to explicitly register every view and controller type with the container. The code for the RegisterAndResolve method is shown below:
Note that editing C# or Razor views inside the MVC application will cause a recompile which does not necessarily cause the application to restart. This can cause a few problems – I find the best approach is to stop the Visual Studio web server whenever I detach or stop debugging.
Now all we need to do is register our new dependency resolver with the MVC framework. The code below comes from the global.asax.cs file and shows the resolver being created, initialised and then registered with the MVC framework. Note that the resolver is registered with itself so that if a type requires IDependencyResolver it will be provided with the instance we have created here.
Now all of your controllers, views etc will be created via the WindsorDependencyResolver, and you will be able to access it anywhere in your MVC application using DependencyResolver.Current.
IControllerActivator
If you want more fine-grained control over how your controllers are created, you can create an implementation of the IControllerActivator interface and register it with the dependency resolver.
Below is an example activator which assumes that all controllers in the application implement the IBaseController interface:
The activator delegates the creation of the controller to the dependency resolver and then performs some custom initialisation logic on the controller.
IModelBinder
Model binding is the process whereby MVC creates model classes and populates them with data from the incoming HTTP request. For example, in the example below the viewModel parameter will be populated by a model binder:
By default to support model binding your model must have a parameterless constructor. If you are using your model as a bridge between the UI and some underlying data classes (as in MVVM) then chances are that your view model will have some dependencies which need to be resolved. For example, the constructor of the AddCustomerViewModel is shown below:
You can override the way that model binding takes place by registering a class implementing IModelBinderProvider with the dependency resolver. This class is responsible for returning a model binder appropriate to the model type. In this instance, we want all model types to be created using the depending resolver, so the model binder provider will always return the same type:
For every model type, this provider will return an instance of ResolvingModelBinder. The code for that class is shown below:
As with the controller activator, this model binder delegates the object creation to the dependency resolver. This means that your models can now use constructor injection.
Do you have any questions or comments on Mark’s approach? Did you find this useful? Would you like more technical tips like this? Let us know in the comments!