为什么 ServiceProvider 无法在 ASP.NET Core 中创建控制器实例?

Lan*_*eyo 4 dependency-injection asp.net-core-mvc asp.net-core

我在 .NET Core 中开发集成测试。由于控制器具有多个依赖项,因此手动创建其实例很不方便。以下是我创建 ServiceProvider 实例以便能够访问 .NET Core 本机 DI 容器的方法:

HostingEnvironment env = new HostingEnvironment();
env.ContentRootPath = Directory.GetCurrentDirectory();
env.EnvironmentName = "Development";

Startup startup = new Startup(env);
ServiceCollection sc = new ServiceCollection();
startup.ConfigureServices(sc);
ServiceProvider = sc.BuildServiceProvider();
Run Code Online (Sandbox Code Playgroud)

Startup类取自经过测试的程序集。

令我惊讶的是,服务提供商无法创建控制器实例。它可以实例化注册的服务,但不能实例化控制器。有人知道为什么会这样吗?

Tse*_*eng 5

您应该使用TestServer,它会引导完整的测试环境(可以选择使用不同的启动类或环境变量,您可以在其中用内存存储替换数据存储)。

ASP.NET Core文档很好地介绍了这种情况。

var server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>()
    // this would cause it to use StartupIntegrationTest or ConfigureServicesIntegrationTest / ConfigureIntegrationTest methods (if existing)
    // rather than Startup, ConfigureServices and Configure
    .UseEnvironment("IntegrationTest"));
Run Code Online (Sandbox Code Playgroud)

在这些替代/依赖于环境的方法中,您可以放置​​集成测试特定的替换/DI 配置。

其次,默认情况下,控制器(以及标签助手和视图组件)不会在 DI 系统中注册。控制器工厂将解析类型。如果您希望通过内置或第 3 方 IoC 容器解析控制器,则必须告诉 ASP.NET Core 显式注册它们(请参阅此相关问题)。

这是一个例子:

services
    .AddMvc()
    .AddControllersAsServices()
    .AddViewComponentsAsServices()
    .AddTagHelpersAsServices();
Run Code Online (Sandbox Code Playgroud)

我建议您使用第一种方法,因为它更加一致,并且这正是Startup具有环境支持的类存在的原因。

更新

重要补充。如果您使用TestServer,您还可以访问其 DI 容器(IServiceProvider实例)。

var server = new TestServer(new WebHostBuilder()
        .UseStartup<Startup>()
        .UseEnvironment("IntegrationTest"));
var controller = server.Host.Services.GetService<MyController>();
Run Code Online (Sandbox Code Playgroud)