Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrations script not using IDesignTimeDbContextFactory #25053

Open
vocko opened this issue Jun 8, 2021 · 11 comments
Open

Migrations script not using IDesignTimeDbContextFactory #25053

vocko opened this issue Jun 8, 2021 · 11 comments
Labels
area-tools customer-reported punted-for-6.0 punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. type-bug
Milestone

Comments

@vocko
Copy link

vocko commented Jun 8, 2021

File a bug

If a class implementing this interface is found in either the same project as the derived DbContext or in the application's startup project, the tools bypass the other ways of creating the DbContext and use the design-time factory instead.

I have a problem with migrations script command failing. It seems it doesn't use the design time factory I have implemented and tries to run the host builder instead (which doesn't have any connection string on the build server).

If I set a (fake) connection string, everything works fine. That makes me thinking the factory is not actually used even though, as the log suggests, it has been noticed by the tools.

Is this a bug or am I doing something wrong?

My factory

It uses the parameterless constructor with no connections string supplied. As it is only used to generate the migrations script, it should all be fine as no db connection is ever needed.

namespace MyApp
{
    public class MyAppDbContextFactory : IDesignTimeDbContextFactory<MyAppDbContext>
    {
        public MyAppDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<MyAppDbContext>();
            optionsBuilder.UseSqlServer();

            return new MyAppDbContext(optionsBuilder.Options);
        }
    }
}

Verbose output

Local paths and project names changed/removed.

dotnet ef migrations script --idempotent --context MyAppDbContext -o migrations.sql --no-build --verbose
Using project '###.csproj'.
Using startup project '###.csproj'.
Writing '###.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=###\AppData\Local\Temp\tmp42B.tmp /verbosity:quiet /nologo ###.csproj
Writing '###.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=###\AppData\Local\Temp\tmp739.tmp /verbosity:quiet /nologo ###.csproj
dotnet exec --depsfile ###\bin\Debug\net5.0\###.deps.json --additionalprobingpath ###\.nuget\packages --additionalprobingpath "C:\Program Files (x86)\DevExpress 20.2\Components\Offline Packages" --runtimeconfig ###\bin\Debug\net5.0\###.runtimeconfig.json ###\.dotnet\tools\.store\dotnet-ef\5.0.6\dotnet-ef\5.0.6\tools\netcoreapp3.1\any\tools\netcoreapp2.0\any\ef.dll migrations script --idempotent --context MyAppDbContext -o migrations.sql --assembly ###\bin\Debug\net5.0\###.dll --startup-assembly ###\bin\Debug\net5.0\###.dll --project-dir ### --language C# --working-dir ### --verbose --root-namespace MyApp
Using assembly 'MyApp'.
Using startup assembly 'MyApp'.
Using application base '###\bin\Debug\net5.0'.
Using working directory '###'.
Using root namespace 'MyApp'.
Using project directory ###'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Found IDesignTimeDbContextFactory implementation 'MyAppDbContextFactory'.
Found DbContext 'MyAppDbContext'.
Finding application service provider in assembly 'MyApp'...
Finding Microsoft.Extensions.Hosting service provider...
Using environment 'Staging'.
Using application service provider from Microsoft.Extensions.Hosting.
System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
   at Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(String value, String parameterName)
   at Microsoft.EntityFrameworkCore.SqlServerDbContextOptionsExtensions.UseSqlServer(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 sqlServerOptionsAction)
   at MyApp.Startup.<ConfigureServices>b__4_0(DbContextOptionsBuilder options) in ###\MyApp\Startup.cs:line 41
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__DisplayClass1_0`2.<AddDbContext>b__0(IServiceProvider p, DbContextOptionsBuilder b)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.CreateDbContextOptions[TContext](IServiceProvider applicationServiceProvider, Action`2 optionsAction)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__DisplayClass17_0`1.<AddCoreServices>b__0(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__17`1.<AddCoreServices>b__17_1(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetServices[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextTypes()
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextType(String name)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.ScriptMigration(String fromMigration, String toMigration, MigrationsSqlGenerationOptions options, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScriptMigrationImpl(String fromMigration, String toMigration, Boolean idempotent, Boolean noTransactions, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScriptMigration.<>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)
Value cannot be null. (Parameter 'connectionString')

Include provider and version information

EF Core version: 5.0.6
Entity Framework Core .NET Command-line Tools 5.0.6
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 5.0
Operating system: Windows 10
IDE: Visual Studio 2019 16.9.4

Pretty sure it is environment independent as I have the same issue on a linux build server.

@bricelam
Copy link
Contributor

  1. We should probably remove the Check.NotEmpty() call since Add parameterless overloads of UseSqlServer, UseSqlite, etc. #8427 was intended to defer the validation of connection strings
  2. We should probably swallow exceptions thrown by services.GetServices<DbContextOptions>() since it is just one of many ways we use to resolve the context name to an actual type.

@replaysMike
Copy link

I'm also seeing this issue, except I'm not quite sure how to get around it.

dotnet ef migrations add InitialCreate --project Data\TestProject.Data --startup-project TestProject.Web

I'm running my web server in a Topshelf service, and when trying to add migrations (.net 6 ef core) it starts my web app passing a bunch of arguments to it, and just stays running with no migrations created.

@pinkfloydx33
Copy link

Same problem with dotnet ef migrations bundle. If I move the Factory into my Database project and omit the startup project on the CLI it works... but the factory needs ConfigurationBuilder + extensions that I don't want to pull into the database project.

@ajcvickers
Copy link
Member

@replaysMike See #27306.

@marchy
Copy link

marchy commented Apr 25, 2022

Not sure in which EF/ASP.NET version this started happening in but our EF migrations have started facing this problem as well.

We are still using the traditional web host builder in Program/Startup var host = WebHost.CreateDefaultBuilder<Startup>( args ) but this did not used to happen prior to our .NET 6 / EFC 6 upgrades.

@stijnherreman
Copy link

Not sure if I'm experiencing the same problem, but migrations remove specifically does not use the IDesignTimeDbContextFactory in my case.

> dotnet ef migrations add Indexes && dotnet format whitespace
Build started...
Build succeeded.
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
Done. To undo this action, use 'ef migrations remove'
> dotnet ef migrations remove        
Build started...
Build succeeded.
System.InvalidOperationException: A relational store has been configured without specifying either the DbConnection or connection string to use.
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.get_DbConnection()
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
   ...

@ajcvickers ajcvickers added the punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. label Sep 13, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, Backlog Sep 13, 2022
@jeffreymb
Copy link

jeffreymb commented Feb 15, 2023

I'm encountering this issue when I have the DbContext set to a scoped service. I get the following error.

System.InvalidOperationException: Cannot resolve scoped service 'Microsoft.EntityFrameworkCore.DbContextOptions`1[Redacted.Core.Configuration.Database.CompanyDbContext]' from root provider.

I think that the IDesignTimeDbContextFactory<TContext> would be the solution to my problem, if it actually worked! I'm on .net 5.0. Is there a way to work around this?

@tecxx
Copy link

tecxx commented Jun 2, 2023

Not sure if I'm experiencing the same problem, but migrations remove specifically does not use the IDesignTimeDbContextFactory in my case.

> dotnet ef migrations add Indexes && dotnet format whitespace
Build started...
Build succeeded.
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
Done. To undo this action, use 'ef migrations remove'
> dotnet ef migrations remove        
Build started...
Build succeeded.
System.InvalidOperationException: A relational store has been configured without specifying either the DbConnection or connection string to use.
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.get_DbConnection()
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
   ...

i believe i run into the same issue. add-migration works, but remove-migration runs into sql connection timeout.

@bricelam bricelam removed their assignment Jul 8, 2023
@davidbuckleyni
Copy link

Am facing the same problem in .net 8 has this not been resolved?

@CristianAtMaersk
Copy link

Same here, my implementation of the IDesignTimeDbContextFactory is found but the DI container is still being constructed and used. Is there a workaround for this? Can I specify in the options to use the IDesignTimeDbContextFactory ?

@AndriySvyryd
Copy link
Member

This is related to #27322

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-tools customer-reported punted-for-6.0 punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. type-bug
Projects
None yet
Development

No branches or pull requests