ConfigureServices
in WebApplicationFactory.ConfigureWebHost
invoked after Startup.ConfigureServices
has been invoked when use generic IHostBuilder CreateHostBuilder
in Program
.
Steps to reproduce the behavior:
Program.cs
the generated code use generic host builder by default in 3.0.public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Microsoft.AspNetCore.Mvc.Testing
package, inherit WebApplicationFactory
and override ConfigureWebHost
follow the docs.ConfigureServices
in Startup
and CustomWebApplicationFactory
.Startup
hit before CustomWebApplicationFactory
. Also the DbContext cannot be overridden like the docs shows.CreateWebHostBuilder
in Startup
with old CreateWebHostBuilder
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
CustomWebApplicationFactory
hit before Startup
.ConfigureServices in WebApplicationFactory should be invoked before Startup.ConfigureServices.
.NET Core SDK (reflecting any global.json):
Version: 3.0.100-preview6-012264
Commit: be3f0c1a03
Runtime Environment:
OS Name: Windows
OS Version: 10.0.18362
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\3.0.100-preview6-012264\
Host (useful for support):
Version: 3.0.0-preview6-27804-01
Commit: fdf81c6faf
.NET Core SDKs installed:
2.1.800-preview-009696 [C:\Program Files\dotnet\sdk]
2.1.800 [C:\Program Files\dotnet\sdk]
2.2.400-preview-010219 [C:\Program Files\dotnet\sdk]
2.2.400 [C:\Program Files\dotnet\sdk]
3.0.100-preview6-012264 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0-preview6.19307.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0-preview6-27804-01 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.0.0-preview6-27804-01 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download
cc @javiercn
@davidfowl This is a result of the move to generic host. Where Startup.ConfigureServices gets called inmmediately. I don't think there's anything we can do about it.
Should you, @Tratcher and me get some time to chat about these changes and what guidance to provide?
I remember having to do some gymnastics to get the Identity UI tests to work with generic host.
I think the biggest change is that Startup.ConfigureServices runs inmmediately, so given that we setup the tests by invoking your builder as the first thing, you can't simply override it later.
For reference, this is how I override the database now:
https://github.com/aspnet/AspNetCore/blob/b9823ed41c8ff23b6dbd233f5cc2a8e5078d2339/src/Identity/test/Identity.FunctionalTests/Infrastructure/FunctionalTestsServiceCollectionExtensions.cs#L24-L55
The main reason to use a custom TStartup is if you need to make incompatible service registrations that are not easy to override (like in our case where we test multiple Identity configurations and call AddIdentity with multiple generic parameters (or not at all)) or when you need to completely replace the Configure pipeline.
I'm not sure at this point if it would make sense to recommend using a different environment, by calling UseEnvironment("Testing") and tell people to write ConfigureTestServices or have them write something like
void ConfigureServices(IServiceCollection collection)
{
if(!HostEnvironment.Environment == "Testing")
{
// Register your services normally
}
}
That way you could theoretically get away with just doing UseStartup
I'm not sure there's anything we can do about it, other than what I did in our own tests. Is there alternative guidance we can provide customers?
So this is about overriding startup completely? Is it about replacing calls to Configure or a ConfigureServices?
@davidfowl In the past, calling UseStartup would replace the original UseStartup class completely, and when you called ConfigureServices on the host builder after UseStartup those would get called before ConfigureServices in UseStartup. (That's why we had ConfigureTestServices)
Now the problem is that users can't simply call UseStartup
I don't think that specifically is a big deal as given that now you always run after you can simply replace the descriptor in the container. (Although a bit inconvenient sometimes).
But the issue remains that there is nothing to prevent the original Startup.ConfigureServices from running, which makes using a TestStartup in your test code painful without changes.
What I did in my code was to take control of calling startup in all my tests and simply add a static flag to Program.cs that I could set before invoking CreateHostBuilder.
That's good for our tests, but it has two problems:
At some point, I think we can discourage people to use TestStartup classes in their tests and simply override the services, but this is not a small change for people with current test suites.
We should do some docs stuff here, but there's no code changed planned for 3.0
I was working on doc updates for 3.0 (aspnet/AspNetCore.Docs #13353). There are a few issues at the moment unrelated to the discussion here that I'm dealing with [e.g., Identity doesn't play well with an in-memory dB, which affects all of our doc samps that use Identity, and the samp is fighting with me 馃 to get UseInternalServiceProvider
to light up).
Notwithstanding those unrelated issues, it sounds like here that the work on this topic+sample should wait until post Pre9. Is that correct? If so, I'll work on those unrelated issues now but I'll sit on my branch until later ... until after this engineering issue is resolved.
What is the guidance for this now?
Using .NET Core 3.0
, I would like to override/replace services configured in my Startup
. Previously I could inherit WebApplicationFactory<Startup>
and use the factories CreateClient
to get a HttpClient
for calling into the test environment.
I'm in the same boat...
System.InvalidOperationException : The TestServer constructor was not called with a IWebHostBuilder so IWebHost is not available.
at Microsoft.AspNetCore.TestHost.TestServer.get_Host()
@niemyjski that looks unrelated to overriding services, please open a different issue. TestServer's relationship to the host is a bit different when working with generic host.
I agree with @Tratcher, this is not the same issue.
I'm closing this issue as the only remaining thing here is to document the new behavior (which is by design) and how to approach the problem when using generic host; and that is being covered by the docs issue https://github.com/aspnet/AspNetCore.Docs/issues/13353
Most helpful comment
What is the guidance for this now?
Using
.NET Core 3.0
, I would like to override/replace services configured in myStartup
. Previously I could inheritWebApplicationFactory<Startup>
and use the factoriesCreateClient
to get aHttpClient
for calling into the test environment.