container.RegisterWebApiControllers(GlobalConfiguration.Configuration)导致出现InvalidOperationException [英] container.RegisterWebApiControllers(GlobalConfiguration.Configuration) causes InvalidOperationException
问题描述
在我的集成测试我使用我在我测试Web API项目建设同样SimpleInjector.Container。
不过,这条线组成的根类:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
导致异常:
System.TypeInitializationException:为MyProject.Api.Test.Integration.HttpClientFactory'的类型初始值引发了异常。
---- System.InvalidOperationException:此方法不能在应用程序的pre-启动初始化阶段被调用。
结果堆栈跟踪:
在MyProject.Api.Test.Integration.HttpClientFactory.Create()
在MyProject.Api.Test.Integration.Controllers.ProductControllerIntegrationTest.<GetProductBar$c$c_Should_Return_Status_BadRequest_When_Bar$c$c_Is_Empty>d__0.MoveNext()在d:\\项目\\我\\ MyProject.Api.Test.Integration \\ \\控制器ProductControllerIntegrationTest.cs:第26行
-----内堆栈跟踪-----
在System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled()
在System.Web.Compilation.BuildManager.GetReferencedAssemblies()
在System.Web.Http.WebHost.WebHostAssembliesResolver.System.Web.Http.Dispatcher.IAssembliesResolver.GetAssemblies()
在System.Web.Http.Dispatcher.DefaultHttpControllerTypeResolver.GetControllerTypes(IAssembliesResolver assembliesResolver)
在System.Web.Http.WebHost.WebHostHttpControllerTypeResolver.GetControllerTypes(IAssembliesResolver assembliesResolver)
在SimpleInjector.SimpleInjectorWebApiExtensions.GetControllerTypesFromConfiguration(HttpConfiguration配置)
在SimpleInjector.SimpleInjectorWebApiExtensions.RegisterWebApiControllers(集装箱货柜,HttpConfiguration配置)
在MyProject.Api.ContainerConfig.RegisterTypes(集装箱货柜)在d:\\项目\\我\\ MyProject.Api \\ App_Start \\ ContainerConfig.cs:128线
在MyProject.Api.ContainerConfig.CreateWebApiContainer()在d:\\项目\\我\\ MyProject.Api \\ App_Start \\ ContainerConfig.cs:行63
在MyProject.Api.Test.Integration.HttpClientFactory..cctor()在d:\\项目\\我\\ MyProject.Api.Test.Integration \\ HttpClientFactory.cs:17行
评论它后一切工作正常,无论是Web应用程序本身和测试。
所以,问题是:
- 什么是异常的原因是什么?
- (而且这种方法真正需要的?)
这里的code为HttpClientFactory(一个辅助类来创建HttpClient的适当标题,如API密钥或授权):
内部静态类HttpClientFactory
{
私人静态只读集装箱_container = ContainerConfig.CreateWebApiContainer(); 公共静态的HttpClient的Create()
{
VAR的客户=新的HttpClient {BaseAddress =的getURL()};
// ...
返回客户端;
}
}
如果我们在堆栈跟踪仔细观察,我们可以确切地看到是怎么回事。在 RegisterWebApiControllers
扩展方法调用上的 GetControllerTypes
方法 IHttpControllerTypeResolver
比如,它从 HttpConfiguration
抓住并传递 IAssembliesResolver
,它也从配置检索。在名为 GetControllerTypes
法(的 WebHostHttpControllerTypeResolver
)调用到 GetControllerTypes
的 DefaultHttpControllerTypeResolver
这将最终导致 GetReferencedAssemblies
一通话的System.Web .Compilation.BuildManager
类。
的 System.Web.Compilation.BuildManager
但是,不能在ASP.NET管道叫早,或ASP.NET在所有的环境之外。既然你是在一个测试中, BuildManage
将抛出您所遇到的除外。
因此溶液(或'绝招',所以你会)这里是替换默认 IAssembliesResolver
时,单元测试。我想,解析看起来是这样的:
公共类TestAssembliesResolver:IAssembliesResolver
{
公众的ICollection&LT;大会&GT; GetAssemblies()
{
返回AppDomain.CurrentDomain.GetAssemblies();
}
}[测试方法]
公共无效TestMethod1()
{
//替换原有IAssembliesResolver。
GlobalConfiguration.Configuration.Services.Replace(typeof运算(IAssembliesResolver)
新TestAssembliesResolver()); 变种容器= SimpleInjectorWebApiInitializer.BuildContainer(); container.Verify();
}
这是有点遗憾的是,你必须处理这一点,特别是因为简单的注射器被设计为可测试。看来,我们用的Web API这么深整合 RegisterWebApiControllers
扩展方法忽略这一点。我们必须退一步想想如何更容易地确认一个单元测试内部的Web API配置。
In my integration tests I'm using the same SimpleInjector.Container which I construct in the Web API project I'm testing.
But this line in composition root class:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
causes an 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.<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
After commenting it everything works fine, both the web app itself and the tests.
So the question is:
- What is the reason for the exception?
- (And is this method really required?)
Here's the code for HttpClientFactory (a helper class to create HttpClient with proper headers, such as api key or authorization):
internal static class HttpClientFactory
{
private static readonly Container _container = ContainerConfig.CreateWebApiContainer();
public static HttpClient Create()
{
var client = new HttpClient { BaseAddress = GetUrl() };
//...
return client;
}
}
If we look closely at the stack trace we can exactly see what is going on here. The RegisterWebApiControllers
extension method calls the GetControllerTypes
method on the IHttpControllerTypeResolver
instance it grabs from the HttpConfiguration
and it passes the IAssembliesResolver
that is also retrieved from the configuration. The called GetControllerTypes
method (of the WebHostHttpControllerTypeResolver
) calls into the GetControllerTypes
of the DefaultHttpControllerTypeResolver
which will eventually cause a call to GetReferencedAssemblies
of the System.Web.Compilation.BuildManager
class.
The System.Web.Compilation.BuildManager
however, can not be called early in the ASP.NET pipeline, or outside the context of ASP.NET at all. Since you're in a test, the BuildManage
will throw the exception you are experiencing.
So the solution (or 'trick' so you will) here is to replace the default IAssembliesResolver
when unit testing. I imagine that resolver to look like this:
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();
}
It's a bit unfortunate that you have to deal this, especially since Simple Injector was designed to be testable. It seems that we overlooked this by integrating the RegisterWebApiControllers
extension method so deeply with Web API. We have to take a step back and think about how to make it easier to verify the Web API configuration inside a unit test.
这篇关于container.RegisterWebApiControllers(GlobalConfiguration.Configuration)导致出现InvalidOperationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!