我们有一个基于ASP.NET MVC 4的应用程序已有几年的历史了,我正在努力摆脱一些技术债务。我正在做的一件事是引入依赖注入,这样我们就可以更好地将业务逻辑与数据访问实现分开,并使编写隔离单元测试变得更加痛苦。我已经选择了Simple Injector,但我遇到了一些问题。
我跟随MVC integration guide in the Simple Injector documentation。它描述了这样的初始化过程:
所以,到目前为止,这是在应用程序中实现的方式。为清晰起见,我删除了日志记录,并为上述步骤添加了标记注释:
// 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);
它成功验证了容器,并且依赖注入也在应用程序中按预期工作。这似乎解决了现在的问题。我还是想知道:
答案 0 :(得分:2)
所以,这是一个有趣的追踪。作为最后的手段,应用程序尝试使用Application_Error
处理未捕获的错误。在Verify()
中完成的Application_Start
方法确实在验证失败时抛出了异常,但这是由Application_Error
方法捕获的(需要弄清楚为什么它不是记录,但这是一个不同的故事)。因此,从未发出对DependencyResolver.SetResolver
的调用。然后,通过管道的实际请求将尝试使用默认控制器激活器。并且所提出的请求当然不是针对导致验证失败的隐藏控制器。
一个控制器也有一个静态构造函数,它缓存了一批只读数据,这些数据不需要为应用程序的每个新请求进行处理。并且该静态构造函数由于一个错误而崩溃,这阻止了该控制器被实例化并使应用程序停止。在以更合理的方式缓存数据并删除静态构造函数之后,验证正常,并且应用程序在根据指南再次进行DI设置时工作正常。