ASP.Net 6 自定义 WebApplicationFactory 抛出异常

Posted

技术标签:

【中文标题】ASP.Net 6 自定义 WebApplicationFactory 抛出异常【英文标题】:ASP.Net 6 custom WebApplicationFactory throws exception 【发布时间】:2021-12-22 20:02:12 【问题描述】:

我正在将现有的 ASP.Net 5 Web 应用程序迁移到 ASP.Net 6,并遇到了让集成测试通过的最后障碍。

我自定义 WebApplicationFactory 并抛出异常:Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.

    public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
    
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        
            Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTests");
            builder.ConfigureServices(services => 
                // Create a new service provider.
                var serviceProvider = new ServiceCollection()
                    .AddEntityFrameworkInMemoryDatabase().AddLogging()
                    .BuildServiceProvider();

                // Add a database context (AppDbContext) using an in-memory database for testing.
                services.AddDbContextPool<AppDbContext>(options =>
                
                    options.UseInMemoryDatabase("InMemoryAppDb");
                    options.UseInternalServiceProvider(serviceProvider);
                    options.EnableSensitiveDataLogging();
                    options.EnableDetailedErrors();
                    options.LogTo(Console.WriteLine);
                );

                services.AddDbContextPool<AppIdentityDbContext>(options =>
                
                    options.UseInMemoryDatabase("InMemoryIdentityDb");
                    options.UseInternalServiceProvider(serviceProvider);
                    options.EnableSensitiveDataLogging();
                    options.EnableDetailedErrors();
                    options.LogTo(Console.WriteLine);
                );
                services.AddScoped<SignInManager<AppUser>>();
                services.AddScoped<ILogger<UserRepository>>(provider => 
                    ILoggerFactory loggerFactory = provider.GetRequiredService<ILoggerFactory>();
                    return loggerFactory.CreateLogger<UserRepository>();
                );
                services.AddDistributedMemoryCache();
                // Build the service provider.
                var sp = services.BuildServiceProvider();

                // Create a scope to obtain a reference to the database contexts
                using (var scope = sp.CreateScope())
                
                    var scopedServices = scope.ServiceProvider;
                    var appDb = scopedServices.GetRequiredService<AppDbContext>();
                    var identityDb = scopedServices.GetRequiredService<AppIdentityDbContext>();
                    var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();

                    // Ensure the database is created.
                    appDb.Database.EnsureCreated();
                    identityDb.Database.EnsureCreated();

                    try
                    
                        // Seed the database with test data.
                        SeedData.PopulateTestData(identityDb);
                        SeedData.PopulateTestData(appDb);
                    
                    catch (Exception ex)
                    
                        logger.LogError(ex, $"An error occurred seeding the " +
                            $"database with test messages. Error: ex.Message");
                    
                
            );
        
    

例外:

  Message: 
    System.NotSupportedException : The content root changed from "C:\Projects\C#\AspNetCoreApi\src\Web.Api\" to "C:\Projects\C#\AspNetCoreApi\test\Web.Api.IntegrationTests\bin\Debug\net6.0\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.

  Stack Trace: 
    ConfigureWebHostBuilder.UseSetting(String key, String value)
    HostingAbstractionsWebHostBuilderExtensions.UseContentRoot(IWebHostBuilder hostBuilder, String contentRoot)
    Program.<Main>$(String[] args) line 58
    --- End of stack trace from previous location ---
    HostingListener.CreateHost()
    <>c__DisplayClass8_0.<ResolveHostFactory>b__0(String[] args)
    DeferredHostBuilder.Build()
    WebApplicationFactory`1.CreateHost(IHostBuilder builder)
    WebApplicationFactory`1.ConfigureHostBuilder(IHostBuilder hostBuilder)
    WebApplicationFactory`1.EnsureServer()
    WebApplicationFactory`1.CreateDefaultClient(DelegatingHandler[] handlers)
    WebApplicationFactory`1.CreateDefaultClient(Uri baseAddress, DelegatingHandler[] handlers)
    WebApplicationFactory`1.CreateClient(WebApplicationFactoryClientOptions options)
    WebApplicationFactory`1.CreateClient()
    MyControllerIntegrationTests.ctor(CustomWebApplicationFactory`1 factory) line 15

感谢任何建议和见解。

【问题讨论】:

我也有同样的问题。我解决它的方法是使用Host.CreateDefaultBuilder(args),它有效,但不是错误消息给出的响应。 错误信息解释了你需要做什么:) 为什么在正确运行应用程序但仅在集成测试期间不会发生此异常?为什么会有如此不同的行为? 【参考方案1】:

由于 Program.cs 中的这一行而发生错误:

builder.WebHost.UseContentRoot(Path.GetFullPath(Directory.GetCurrentDirectory())); // Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.

我添加这个是因为我想保留args,因此我使用了WebApplication.CreateBuilder(args)。感谢@davidfowl,我改用了以下代码 sn-p:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions

    ApplicationName = typeof(Program).Assembly.FullName,
    ContentRootPath = Path.GetFullPath(Directory.GetCurrentDirectory()),
    WebRootPath = "wwwroot",
    Args = args
);

并删除了错误的代码行。请注意,只要输入参数与默认值不同,builder.WebHost.UseContentRoot 就会抛出异常。就我而言,它在运行集成测试时抛出异常,但在运行应用程序时不会抛出异常。

【讨论】:

这为我解决了另一个问题,当我将 .NET 6 应用程序部署到 Azure Web 应用程序时,我会得到一个 DirectoryNotFoundException(它出于某种原因查看了 D 驱动器,但我仍然没有)不懂)。非常感谢您为解决这个头痛问题提供了解决方案

以上是关于ASP.Net 6 自定义 WebApplicationFactory 抛出异常的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET 5 MVC 6 RC1 API 中的自定义模型绑定异常

在 ASP.NET 5 (vNext) MVC 6 中实现自定义路由器

ASP.NET 最小 API - 访问 IConfiguration

《ASP.NET Core 6框架揭秘》实例演示[28]:自定义一个服务器

《ASP.NET Core 6框架揭秘》实例演示[04]:自定义依赖注入框架

ASP.NET MVC Core/6:多个提交按钮