Repository navigation
System.InvalidOperationException: Unable to build IHost when creating EF Migration with Minimal API dotnet 6 #60891
Description
Description
I have an issue when creating ef migrations for the newest release candidate 6.0.0-rc.2.21480.5 for dotnet 6 with the minimal apis. It seems to be a similar issue as explained here dotnet/aspnetcore#33886
The timeout for creating a WebApplicationFactory at design time seems to be 5 sec and that is not enough for me when I add new migrations, because I need to setup a lot of configuration before. I get this exception when trying to run any command that requires the project to be build like dotnet ef migrations add AddedPlanningSessions -v and the DbContext to be fetched from the service provider. I would expect there to be no timeout at all or at least a very large one when using WebApplicationFactory at design time.
System.InvalidOperationException: Unable to build IHost
at Microsoft.Extensions.Hosting.HostFactoryResolver.HostingListener.CreateHost()
at Microsoft.Extensions.Hosting.HostFactoryResolver.<>c__DisplayClass8_0.<ResolveHostFactory>b__0(String[] args)
at Microsoft.Extensions.Hosting.HostFactoryResolver.<>c__DisplayClass11_0.<ResolveServiceProviderFactory>b__3(String[] args)
at Microsoft.EntityFrameworkCore.Design.Internal.AppServiceProviderFactory.CreateFromHosting(String[] args)
The issue can be easily reproduced by creating an empty project with minimal api dotnet new web -o service, adding a dbcontext to the DI and adding a sleep of 6 sec.
Include your code
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer("localhost"));
Thread.Sleep(TimeSpan.FromSeconds(6));
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();Include verbose output
Output when building my project where the steps until builder.Build() take too long.
dotnet exec --depsfile /Users/ian/Repos/work/planner-service/service/bin/Debug/net6.0/service.deps.json --additionalprobingpath /Users/ian/.nuget/packages --additionalprobingpath /usr/local/share/dotnet/sdk/NuGetFallbackFolder --runtimeconfig /Users/ian/Repos/work/planner-service/service/bin/Debug/net6.0/service.runtimeconfig.json /Users/ian/.dotnet/tools/.store/dotnet-ef/6.0.0-rc.2.21480.5/dotnet-ef/6.0.0-rc.2.21480.5/tools/netcoreapp3.1/any/tools/netcoreapp2.0/any/ef.dll dbcontext info --assembly /Users/ian/Repos/work/planner-service/service/bin/Debug/net6.0/service.dll --project /Users/ian/Repos/work/planner-service/service/service.csproj --startup-assembly /Users/ian/Repos/work/planner-service/service/bin/Debug/net6.0/service.dll --startup-project /Users/ian/Repos/work/planner-service/service/service.csproj --project-dir /Users/ian/Repos/work/planner-service/service/ --root-namespace PlannerService --language C# --framework net6.0 --nullable --working-dir /Users/ian/Repos/work/planner-service/service --verbose
Using assembly 'service'.
Using startup assembly 'service'.
Using application base '/Users/ian/Repos/work/planner-service/service/bin/Debug/net6.0'.
Using working directory '/Users/ian/Repos/work/planner-service/service'.
Using root namespace 'PlannerService'.
Using project directory '/Users/ian/Repos/work/planner-service/service/'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider in assembly 'service'...
Finding Microsoft.Extensions.Hosting service provider...
Using environment 'Development'.
Loading config from: global, planner-service.
System.InvalidOperationException: Unable to build IHost
at Microsoft.Extensions.Hosting.HostFactoryResolver.HostingListener.CreateHost()
at Microsoft.Extensions.Hosting.HostFactoryResolver.<>c__DisplayClass8_0.<ResolveHostFactory>b__0(String[] args)
at Microsoft.Extensions.Hosting.HostFactoryResolver.<>c__DisplayClass11_0.<ResolveServiceProviderFactory>b__3(String[] args)
at Microsoft.EntityFrameworkCore.Design.Internal.AppServiceProviderFactory.CreateFromHosting(String[] args)
An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the application service provider. Error: Unable to build IHost
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'PlannerContext'.
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'PlannerContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
---> System.InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[PlannerService.DAL.PlannerContext]' while attempting to activate 'PlannerService.DAL.PlannerContext'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass21_4.<FindContextTypes>b__13()
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass21_4.<FindContextTypes>b__13()
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.GetContextInfo(String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.GetContextInfoImpl(String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.GetContextInfo.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Unable to create an object of type 'PlannerContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Include provider and version information
EF Core version: 6.0.0-rc.2.21480.5
Database provider: Microsoft.EntityFrameworkCore.SqlServer 6.0.0-rc.2.21480.5
Target framework: NET 6.0
Operating system:
IDE: VS Code Version: 1.61.1
Activity
ajcvickers commentedon Oct 22, 2021
/cc @davidfowl
davidfowl commentedon Oct 22, 2021
This is a tough one as we need to tradeoff how much is too much time before we give up waiting for the host builder to be created... It's possible we need an environment variable override for these cases.
@ajcvickers Do you have a preference for where this gets fixed? I think we'd add support for an environment variable to override the timeout for cases like this. EF can provide a different timeout here
cc @maryamariyan @eerhardt
ajcvickers commentedon Oct 22, 2021
@davidfowl I don't have strong preferences. If you provide the mechanism, we can make use of it.
davidfowl commentedon Oct 22, 2021
https://github.com/dotnet/efcore/blob/8144d50ec0d15b87c35a9a3a425b1faadafb87f1/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs#L53
I can think of 2 things:
eerhardt commentedon Oct 22, 2021
Is 5 seconds a reasonable default? Seems pretty low to me
davidfowl commentedon Oct 22, 2021
Yea, maybe it's too small. What should the default be?
ajcvickers commentedon Oct 23, 2021
What are the scenarios in which we expect this to timeout? I assume that it is when the application does not actually use hosting, right? But then, more specifically for EF, the question is whether or not we have to wait for the timeout if the EF model is discovered in some other way. For example, do we have to wait for the timeout if:
I think if those two cases work without waiting for the timeout, then having a longer timeout is okay, because we will only cause slowness in real negative cases where we are going to show an error anyway.
It seems like we need to do some investigation here into the user experience.
/cc @bricelam
davidfowl commentedon Oct 23, 2021
The timeout is only there for this edge case:
The user runs the EF tool on a .NET 6.0 application that references hosting but doesn't use it in the main entry point. Maybe its ok hanging in this scenario with a message on what the user can do?
ajcvickers commentedon Oct 25, 2021
@davidfowl In that case, it seems like you can just increase the timeout significantly. If all context discovery fails, then we will output:
As shown above.
davidfowl commentedon Oct 26, 2021
Right but it wouldn't show that message. It would just hang forever unless other changes were made to show the message after some timeout
ajcvickers commentedon Oct 26, 2021
@davidfowl I don't mean make the timeout infinite. I just mean increase it significantly, to say 20 or 30 seconds. It will then timeout and show the message. The user can then implement a design time context factory, in which case they can hopefully resolve the EF model quicker, or, at least, let it take as long as necessary without any timeout.
davidfowl commentedon Oct 26, 2021
Lets do that then. @eerhardt We should also change the default in the HostFactoryResolver as well (even though it's shared source).
davidfowl commentedon Oct 26, 2021
cc @captainsafia @maryamariyan
eerhardt commentedon Oct 26, 2021
Should this issue get moved to dotnet/runtime then? Or is there a change EF should make here as well?
ajcvickers commentedon Oct 26, 2021
@eerhardt As far as I know, it should move to runtime. EF will pick up the new source from there.
5 remaining items
maryamariyan commentedon Oct 28, 2021
Next to do here based on earlier conversation
is to increase timeout. On top of that we could consider adding an environment variable that could help developers set custom timeout
davidfowl commentedon Nov 11, 2021
@ghorsey-opt this won't help but you can remove ConfigureAppConfiguration and just use builder.Configuration to clean up the code a bit
davidfowl commentedon Nov 11, 2021
We're gonna fix the bug in a 6.0.x patch.
halter73 commentedon Nov 15, 2021
I think the main thing we need to do is improve the exception message.
System.InvalidOperationException: Unable to build IHostdoes not make it clear there was a 5 second timeout waiting for Program.Main() to actually build the IHost. Adding remediation options to the exception message like setting a new environment variable to increase the timeout will help a lot.I'm not sure most users want to wait 20-30 seconds to load the IHost for EF migrations. I get that's the max before it times out, but it would be nice to let developers know that reducing the time spent in Program.Main() before building the IHost will speed up migrations rather than leave people to wonder why migrations are now slower.
Maybe we could consider adding a command line argument to indicate that it's being resolved by the HostFactoryResolver so developers can short-circuit unnecessary startup logic when just setting up DB services for doing migrations. We already add
--applicationName, so maybe the exception message could reference that.