如何使用Simple Injector装饰ASP.NET MVC控制器

Mar*_*ich 8 asp.net-mvc simple-injector

我想对我的MVC控制器应用一些横切关注点.目前,这是通过抽象基类实现的,但是当我们重构更多代码库以利用依赖注入时,我想知道这是否是Simple Injector可以帮助我通过它的装饰或拦截设施.

所以我试图创建一个非常基本的装饰器:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的作文根: container.RegisterDecorator<IController, ControllerDecorator>()

但是,我的装饰器Execute方法中的代码似乎永远不会被调用.是因为MVC框架直接解析我的控制器类而不是通过IController?在那种情况下,我该怎么办?我在这里错过了什么?

Ste*_*ven 10

在默认配置中,您无法将装饰器应用于控制器.原因是MVC DefaultControllerFactory按其具体类型请求控制器.因为它请求具体类型,Simple Injector无法应用装饰器; 它必须假设调用者需要这种具体类型,因此必须返回这种确切的类型(或子类型).

要解决此问题,您必须DefaultControllerFactory使用自定义替换默认值:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来,在您的引导程序中,您必须RegisterMvcControllers使用以下内容替换调用:

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 });
Run Code Online (Sandbox Code Playgroud)

CreateControllerProducer方法如下:

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;
}
Run Code Online (Sandbox Code Playgroud)

最关键的部分是将呼叫CreateProducer与供应typeof(IController); 这允许Simple Injector应用装饰器IController.

就是这个; 现在你可以注册你的装饰IController.

但是有一个警告:使用Web API和新的ASP.NET核心都不可能将装饰器应用于控制器.两个框架都期望具体类型; 如果你包装真正的控制器它们会破裂.这些框架装饰控制器的首选方法是通过OWIN管道.所以这个答案仅适用于MVC 3,4和5.