I\'d like to apply some cross-cutting concerns to my MVC controllers. At the moment, this is implemented through an abstract base class, but as we are refactoring more of th
In the default configuration, you can't apply decorators to controllers. The reason for this is that MVC's DefaultControllerFactory
requests controllers by their concrete type. Because it requests a concrete type, Simple Injector is unable to apply a decorator; it has to assume that the caller needs this concrete type and has to therefore return this exact type (or a sub type).
To fix this, you will have to replace the default DefaultControllerFactory
with a custom one:
public class SimpleInjectorControllerFactory : DefaultControllerFactory {
public IDictionary<Type, InstanceProducer> Producers { get; set; }
protected override IController GetControllerInstance(RequestContext rc, Type type) {
return (IController)this.Producers[type].GetInstance();
}
}
Next, in your bootstrapper, you'll have to replace the call to RegisterMvcControllers
with the following:
var controllerTypes = SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly());
var controllerProducers = controllerTypes
.ToDictionary(type => type, type => CreateControllerProducer(container, type));
// Verify after creating the controller producers.
container.Verify();
ControllerBuilder.Current.SetControllerFactory(
new SimpleInjectorControllerFactory { Producers = controllerProducers });
The CreateControllerProducer
method looks as follows:
private static InstanceProducer CreateControllerProducer(Container c, Type type) {
var producer = Lifestyle.Transient.CreateProducer(typeof(IController), type, c);
producer.Registration.SuppressDiagnosticWarning(
DiagnosticType.DisposableTransientComponent,
"MVC disposes the controller when the web request ends.");
return producer;
}
The crucial part is that the call to CreateProducer
is supplied with typeof(IController)
; this allows Simple Injector to apply a decorator for IController
.
This is it; now you can register your decorator for IController
.
One warning though: with both Web API and the new ASP.NET core it is impossible to apply decorators to controllers. Both frameworks expect concrete types; they will break if you wrap the real controller. The preferred way with those frameworks to decorate controllers is through the OWIN pipeline. So this answer solely works with MVC 3, 4 and 5.