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
)调用DefaultHttpControllerTypeResolver
的GetControllerTypes
,最终将调用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() );
..所以现在它知道要搜索控制器的程序集。