0

I want to add migrations to the project, so I've implemented the IDesignTimeDbContextFactory interface to it.

I've placed the ContextFactory in the presentation layer of the project, where the context is in de database layer.

In the start up I inject the contexts connection string like this:

services.AddTransient<FooDbContext>().AddDbContext<FooDbContext>(options => options.UseSqlServer(Environment.GetEnvironmentVariable("FOODB_CONNECTIONSTRING")));

The ContextFactory (for migration is implemented like this):

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<FooDbContext>
{
    public WegisterDbContext CreateDbContext(string[] args)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();

        var builder = new DbContextOptionsBuilder<FooDbContext>();

        var connectionString = configuration.GetConnectionString("DefaultConnection");

        builder.UseSqlServer(connectionString);

        return new FooDbContext(builder.Options);
    }
}

So if I comment out the injection in the startup, I'm able to run the migration, but with this code active, I get this error:

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, Action1 sqlServerOptionsAction) at Wegister.Startup.<>c.<ConfigureServices>b__7_1(DbContextOptionsBuilder options) in C:\Users\Daphne\Source\Repos\SalomeCodes\Wegister\Wegister\Wegister\Startup.cs:line 66 at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__DisplayClass1_02.b__0(IServiceProvider p, DbContextOptionsBuilder b)
at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.CreateDbContextOptions[TContext](IServiceProvider applicationServiceProvider, Action2 optionsAction) at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__DisplayClass10_01.b__0(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.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.CallSiteVisitor2.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.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__101.<AddCoreServices>b__10_1(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.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.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.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.CallSiteVisitor2.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.AddMigration(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_01.b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Value cannot be null. (Parameter 'connectionString')

So the dependency injection overrides this connection string - but why?

What is the solution so I'm still possible to run code and migrate? Because when I start the code with the dependency injection on the connection string the application doesn't know where to connect with?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
SaloméCodes
  • 57
  • 1
  • 9
  • Have you checked that `configuration.GetConnectionString("DefaultConnection")` returns not null string? – Guru Stron Jul 04 '20 at 19:33
  • Yes it is set, although I can't set the appsettings.json variables at runtime right? so docker run --env DefaultConnection=foo.nletc isn't going to work right? So actually I want to be possible to set the string dynamically. – SaloméCodes Jul 04 '20 at 19:39
  • Isn't there an easier way than this: https://stackoverflow.com/questions/46085500/injecting-env-conn-string-into-net-core-2-0-w-ef-core-dbcontext-in-different-cl ? – SaloméCodes Jul 04 '20 at 19:41
  • Can you share appsettings.json – Vivek Nuna Jul 04 '20 at 19:50
  • Yes but it's not in the appsettings.json it works if i remove the dependency injection in my Startup where I also add the connectionstring. – SaloméCodes Jul 04 '20 at 20:00
  • 1
    @SaloméCodes if you have added environment variables as configuration provider after config files ( or using [default one](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#default-configuration)), then `docker run --env` should work. As for example you've provided, `IDesignTimeDbContextFactory` there used in separate assembly, not the one containing `Startup` as far as I understand. – Guru Stron Jul 04 '20 at 20:08
  • Oh indeed, thanks! this was just a lack of knowledge.. sorry. I also read that launchsettings.json are just for visual studio. So I can set my environment variables in Appsettings.json with the `docker run --env` command? – SaloméCodes Jul 04 '20 at 20:10
  • 1
    1) `launchsettings.json` are for development environments (VS and Rider supports it) 2) no, it will not set anything in `appsettings.json` you can add environment variables with `.AddEnvironmentVariables();` if you call it after `AddJsonFile` then existing anv vars will be used "overriding" what is written in json file. – Guru Stron Jul 04 '20 at 20:21

1 Answers1

0

Solved it with this piece of code in the start up:

IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();

var connstring = Configuration["WEGISTERDB_CONNECTIONSTRING"] ?? configuration.GetConnectionString("WEGISTERDB_CONNECTIONSTRING");

It made it possible to remove the IDesignTimeDbContextFactory as well.. Somehow migrations need a connectionstring which is already set, because it can't get connectionstrings as environment variable.

SaloméCodes
  • 57
  • 1
  • 9