如果在为MVC 4

时间:2015-06-23 13:49:47

标签: asp.net-mvc-4 dependency-injection simple-injector

我们有一个基于ASP.NET MVC 4的应用程序已有几年的历史了,我正在努力摆脱一些技术债务。我正在做的一件事是引入依赖注入,这样我们就可以更好地将业务逻辑与数据访问实现分开,并使编写隔离单元测试变得更加痛苦。我已经选择了Simple Injector,但我遇到了一些问题。

我跟随MVC integration guide in the Simple Injector documentation。它描述了这样的初始化过程:

  1. 创建容器
  2. 在容器中注册类型
  3. 验证容器(可选)
  4. 覆盖默认依赖项解析程序
  5. 所以,到目前为止,这是在应用程序中实现的方式。为清晰起见,我删除了日志记录,并为上述步骤添加了标记注释:

    // 1
    var container = new Container();
    var webRequestLifestyle = new WebRequestLifestyle();
    
    // 2
    container.Register<IOrganizationService>(
        delegate
        {
            var proxy = new OrganizationServiceProxy(
                organizationServiceManagement, clientCredentials);
            proxy.EnableProxyTypes();
            return proxy;
        },
        webRequestLifestyle);
    
    container.RegisterSingle<ILoggerProvider>(LoggerProvider); // static field
    container.Register<IExternalLinkRepository, ExternalLinkRepository>(webRequestLifestyle);
    container.Register<IQueueRepository, QueueRepository>(webRequestLifestyle);
    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    container.RegisterMvcIntegratedFilterProvider();
    
    // 3
    container.Verify(VerificationOption.VerifyAndDiagnose);
    
    // 4
    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    

    尝试实例化MVC控制器时,上面的代码在步骤3失败,抛出System.InvalidOperationException: An error occurred when trying to create a controller of type 'MyProject.MyNamespace.MyController'. Make sure that the controller has a parameterless public constructor.

    这是有道理的,因为我的控制器是为构造函数注入而设置的。例如:

    public MyController(ILoggerProvider loggerProvider)
    {
        Logger = loggerProvider.Get(GetType());
    }
    

    默认的MVC控制器激活器不知道该如何处理。但是,我不明白的是为什么Simple Injector的Container.Verify方法完全击中了MVC的默认控制器激活器。容器本身不应该使用Simple Injector的依赖性解析来测试依赖图吗?查看异常调用堆栈,它起源于System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create,因此它在某些时候肯定超出了Simple Injector的范围。

    然而,当我交换步骤3和4的顺序时:

    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    container.Verify(VerificationOption.VerifyAndDiagnose);
    

    它成功验证了容器,并且依赖注入也在应用程序中按预期工作。这似乎解决了现在的问题。我还是想知道:

    1. 为什么Simple Injector使用MVC的默认控制器激活器来测试依赖关系解析?这是预期/记录在哪里吗?
    2. 首先设置自定义解析器,然后验证是否有任何副作用?我问,因为这与文档中的指南相反。它似乎按预期工作,如果它们中的任何一个失败,应用程序仍然会崩溃,所以从应用程序的角度看它似乎并不重要。

1 个答案:

答案 0 :(得分:2)

所以,这是一个有趣的追踪。作为最后的手段,应用程序尝试使用Application_Error处理未捕获的错误。在Verify()中完成的Application_Start方法确实在验证失败时抛出了异常,但这是由Application_Error方法捕获的(需要弄清楚为什么它不是记录,但这是一个不同的故事)。因此,从未发出对DependencyResolver.SetResolver的调用。然后,通过管道的实际请求将尝试使用默认控制器激活器。并且所提出的请求当然不是针对导致验证失败的隐藏控制器。

一个控制器也有一个静态构造函数,它缓存了一批只读数据,这些数据不需要为应用程序的每个新请求进行处理。并且该静态构造函数由于一个错误而崩溃,这阻止了该控制器被实例化并使应用程序停止。在以更合理的方式缓存数据并删除静态构造函数之后,验证正常,并且应用程序在根据指南再次进行DI设置时工作正常。