container.RegisterWebApiControllers(GlobalConfiguration.Configuration)导致InvalidOperationException

在我的集成测试中,我使用的是我正在测试的Web API项目中构建的相同的SimpleInjector.Container。

但是这一行在组合根类中:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

导致exception:

 System.TypeInitializationException : The type initializer for 'MyProject.Api.Test.Integration.HttpClientFactory' threw an exception. ---- System.InvalidOperationException : This method cannot be called during the application's pre-start initialization phase. Result StackTrace: at MyProject.Api.Test.Integration.HttpClientFactory.Create() at MyProject.Api.Test.Integration.Controllers.ProductControllerIntegrationTest.d__0.MoveNext() in d:\Projects\My\MyProject.Api.Test.Integration\Controllers\ProductControllerIntegrationTest.cs:line 26 ----- Inner Stack Trace ----- at System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() at System.Web.Compilation.BuildManager.GetReferencedAssemblies() at System.Web.Http.WebHost.WebHostAssembliesResolver.System.Web.Http.Dispatcher.IAssembliesResolver.GetAssemblies() at System.Web.Http.Dispatcher.DefaultHttpControllerTypeResolver.GetControllerTypes(IAssembliesResolver assembliesResolver) at System.Web.Http.WebHost.WebHostHttpControllerTypeResolver.GetControllerTypes(IAssembliesResolver assembliesResolver) at SimpleInjector.SimpleInjectorWebApiExtensions.GetControllerTypesFromConfiguration(HttpConfiguration configuration) at SimpleInjector.SimpleInjectorWebApiExtensions.RegisterWebApiControllers(Container container, HttpConfiguration configuration) at MyProject.Api.ContainerConfig.RegisterTypes(Container container) in d:\Projects\My\MyProject.Api\App_Start\ContainerConfig.cs:line 128 at MyProject.Api.ContainerConfig.CreateWebApiContainer() in d:\Projects\My\MyProject.Api\App_Start\ContainerConfig.cs:line 63 at MyProject.Api.Test.Integration.HttpClientFactory..cctor() in d:\Projects\My\MyProject.Api.Test.Integration\HttpClientFactory.cs:line 17 

评论之后一切正常,网络应用程序本身和测试。

所以问题是:

  • exception的原因是什么?
  • (这种方法真的需要吗?)

这是HttpClientFactory的代码(一个辅助类,用于创建具有适当头的HttpClient,例如api密钥或授权):

 internal static class HttpClientFactory { private static readonly Container _container = ContainerConfig.CreateWebApiContainer(); public static HttpClient Create() { var client = new HttpClient { BaseAddress = GetUrl() }; //... return client; } } 

如果我们仔细观察堆栈跟踪,我们可以准确地看到这里发生了什么。 RegisterWebApiControllers扩展方法在从IHttpControllerTypeResolver实例上调用GetControllerTypes方法,并传递也从配置中检索的IAssembliesResolver 。 调用GetControllerTypes方法( WebHostHttpControllerTypeResolver )调用DefaultHttpControllerTypeResolverGetControllerTypes ,最终将调用System.Web.Compilation.BuildManager类的GetReferencedAssemblies

但是, System.Web.Compilation.BuildManager不能在ASP.NET管道的早期调用,也不能在ASP.NET的上下文之外调用。 由于您正在进行测试, BuildManage将抛出您遇到的exception。

因此,这里的解决方案(或“技巧”)将在unit testing时替换默认的IAssembliesResolver 。 我认为旋转变压器看起来像这样:

 public class TestAssembliesResolver : IAssembliesResolver { public ICollection GetAssemblies() { return AppDomain.CurrentDomain.GetAssemblies(); } } [TestMethod] public void TestMethod1() { // Replace the original IAssembliesResolver. GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new TestAssembliesResolver()); var container = SimpleInjectorWebApiInitializer.BuildContainer(); container.Verify(); } 

你不得不处理这个问题有点不幸,特别是因为Simple Injector的设计是可测试的。 我们似乎忽略了这一点,将RegisterWebApiControllers扩展方法与Web API深深地集成在一起。 我们必须退一步思考如何更轻松地validationunit testing中的Web API配置。

SI v3.x的解决方案就是……

 container.RegisterWebApiControllers( GlobalConfiguration.Configuration, Assembly.GetExecutingAssembly() ); 

..所以现在它知道要搜索控制器的程序集。