The MVC 3.0 IDependencyResolver interface is broken. Don’t use it with Windsor.
I’ve been spending today moving Suteki Shop to MVC 3. One of the cool new features of MVC 3 is a much greater focus on allowing the various components (Controllers, Views, Filters etc) to be composed by an IoC container. It’s been possible since MVC 1 to provide your own custom controller factory, but the promise with MVC 3 is that you can provide an implementation of IDependencyResolver that wraps your IoC container of choice, and no longer have to bother about implementing various factory classes.
Here’s IDependencyResolver:
public interface IDependencyResolver {
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
But there’s a huge problem with this. Can you spot it? That’s right, no ‘Release’ method. You can provide a service from your IoC container, but there’s no way to clean it up. If I was going to use this in Suteki Shop, I would have a memory leak of epic proportions.
According to the MVC team, this isn’t an issue because they will call ‘Dispose’ on any service that implements IDisposable, but that won’t work in many cases. Let me explain. Say I’ve got a controller like this:
public class HomeController : IController
{
private readonly ICustomerRepository customerRepository;
public HomeController(ICustomerRepository customerRepository)
{
this.customerRepository = customerRepository;
}
// ... does some stuff with customerRepository
}
My controller doesn’t implement IDisposable. So no Dispose method gets called.
public class CustomerRepository : ICustomerRepository, IDisposable
{
// ... etc
}
CustomerRepository does implement IDisposable. But the MVC framework doesn’t know this, indeed my HomeController doesn’t know it either. That’s the whole point of using an IoC container in the first place, it worries about component lifecycles, not the client service. If I resolve HomeController from Windsor it will create all its dependencies and if it finds any that implement IDisposable it will track the entire dependency graph. If I then call ‘Release’ on my HomeController instance, Windsor will know to dispose of CustomerRepository correctly. But if Release is never called CustomerRepository will never get disposed and my web application will gradually consume more and more memory, database connections, file handles, or whatever should have been cleaned up when Dispose gets called.
0 comments