我在asp.net core startup.cs文件中有如下注册:
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterType<UserService>().As<IUserService>();
}
这是配置Autofac容器。我还有另一个集成测试项目,其中有一个 CustomWebApplicationFactory 类,我正在尝试替换 IUserService 接口(interface)的实现。
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
services.AddSingleton<IUserService, TestUsersService>();
});
}
我在调试测试项目的时候好像不行,IUserService的实现还是UserService。
我尝试使用 ASP.NET Core 内置的 IServiceCollection 在 Startup.ConfigureServices 方法中直接注册 UserService,它在调试时有效:
services.AddSingleton<IUserService, UserService>();
那么,当我使用 Autofac 作为 IoC 容器时,如何解决这个问题,集成测试项目会像我预期的那样正常运行?
最佳答案
您可能会遇到操作顺序问题。一般来说,最后获胜。这适用于 Autofac 和基本的 Microsoft DI 容器。
假设you've read through the docs on Autofac ASP.NET Core integration您会看到,当 ConfigureContainer
到位时,操作顺序大致为:
- WebHost 特定的配置服务
- 启动类ConfigureServices
- 启动类ConfigureContainer
当添加 ConfigureTestServices 时,它看起来像(虽然我还没有逐步完成)它在 WebHost 和 Startup 类 ConfigureServices 之后运行...但它仍然在 ConfigureContainer 之前运行。
这很容易测试 - 创建一个具有三种不同实现的服务接口(interface)。在每个级别注册不同的实现。解析 Controller 中的接口(interface)。你得到了哪一个?那是最后一个跑的。现在从应用程序中删除该注册并重试。你得到的下一个是什么?这是倒数第二个。等等。
Autofac 采用预构建的 IServicesCollection
并循环遍历它,将其添加到 native Autofac 容器中。一旦发生这种情况,修改集合就没有关系了。 Autofac 无法控制 ASP.NET Core 中启动机制的执行顺序;它只知道 ASP.NET Core 说,“这是要继续导入的最终服务集合!”如果在正确的阶段没有发生这种情况,您将必须执行以下两项操作之一:
- 将您需要覆盖的注册从
ConfigureContainer
移到其中一个ConfigureServices
方法中,使用 Microsoft 注册语言而不是 native Autofac。 - 以其他方式执行覆盖,例如使用
Test
的ASPNETCORE_ENVIRONMENT
设置并提供ConfigureTestContainer
方法。 (环境特定注册方法的示例在 the docs 中。)
关于c# - 如何在 ASP.NET Core 集成测试中覆盖来自其他容器的 DI 注册,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51856614/