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

标签 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 的代码(一个帮助程序类,用于创建具有适当 header 的 HttpClient,例如 api key 或授权):

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)调用 DefaultHttpControllerTypeResolverGetControllerTypes 最终会导致调用到 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 配置。

关于c# - container.RegisterWebApiControllers(GlobalConfiguration.Configuration) 导致 InvalidOperationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26704486/

相关文章:

c# - 在 C# 中将 base64 字符串转换为 long

dependency-injection - Aurelia & Typescript 注入(inject)和继承

xamarin.ios - Monotouch 使用 ASP.NET Web Api

c# - 从 App.OnStartup 调用异步 Web API 方法

c# - WebAPI 异步方法错误

Symfony DI 调用静态方法

c# - 简单注入(inject)器依赖解析错误 - 无法加载文件或程序集 System.Web.Http

c# - 来自 BinaryFormatter.Deserialize 的 OutOfMemory 异常来自其内部 StringBuilder 调用

c# - 有条件地为 child 启用/禁用自动格式化

c# - ASP .NET C# MVC 5 代码优先外键属性/列名称