C# · 12月 22, 2021

c# – container.RegisterWebApiControllers(GlobalConfiguration.Configuration)导致InvalidOperationException

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

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

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

导致异常:

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.<GetProductBarcode_Should_Return_Status_BadRequest_When_Barcode_Is_Empty>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

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

所以问题是:

>例外的原因是什么?
>(这种方法真的需要吗?)

这是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扩展方法在从HttpConfiguration获取的IHttpControllerTypeResolver实例上调用GetControllerTypes方法,并传递也从配置中检索的IAssembliesResolver.调用GetControllerTypes方法(WebHostHttpControllerTypeResolver)调用DefaultHttpControllerTypeResolver的GetControllerTypes,最终将调用System.Web.Compilation.BuildManager类的GetReferencedAssemblies.

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

所以这里的解决方案(或’技巧’)将在单元测试时替换默认的IAssembliesResolver.我认为旋转变压器看起来像这样:

public class TestAssembliesResolver : IAssembliesResolver{ public ICollection<Assembly> 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深深地集成在一起.我们必须退后一步,思考如何更轻松地验证单元测试中的Web API配置.