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 the code base to take advantage of dependency injection, I'm wondering if this is something Simple Injector can help me with through its decoration or interception facilities.
So I've attempted to create a pretty basic decorator:
public class ControllerDecorator : IController
{
private readonly IController _controller;
public ControllerDecorator(IController controller)
{
_controller = controller;
}
public void Execute(RequestContext requestContext)
{
// Do something of a cross-cutting nature here...
_controller.Execute(requestContext);
}
}
And in my composition root: container.RegisterDecorator<IController, ControllerDecorator>()
However, the code in my decorator's Execute
method doesn't seem to ever get called. Is it because the MVC framework directly resolves my controller classes instead of going through IController
? In that case, what can I do? What am I missing here?
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:Next, in your bootstrapper, you'll have to replace the call to
RegisterMvcControllers
with the following:The
CreateControllerProducer
method looks as follows:The crucial part is that the call to
CreateProducer
is supplied withtypeof(IController)
; this allows Simple Injector to apply a decorator forIController
.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.