container.RegisterWebApiControllers(GlobalConfiguration.Configuration)导致InvalidOperationException

时间:2014-11-02 21:13:10

标签: c# asp.net-web-api dependency-injection simple-injector

在我的集成测试中,我使用的是我正在测试的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;
    }
}

2 个答案:

答案 0 :(得分:6)

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

然而,System.Web.Compilation.BuildManager不能在ASP.NET管道的早期调用,也不能在ASP.NET的上下文之外调用。由于您正在参加考试,BuildManage会抛出您遇到的异常。

所以解决方案(或者诀窍&#39;所以你会这样做)在单元测试时替换默认的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配置。

答案 1 :(得分:3)

SI v3.x的解决方案只是......

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

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

相关问题