entity-frameworkentity-framework-core

Constructor injection into IDesignTimeDbContextFactory


I'm attempting to use migrations EFCore2.0 in a .NET standard 2.0 class library, and so far I have something like

public class SomeContextFactory : IDesignTimeDbContextFactory<SomeContext>
{
    private Configuration _configuration;

    public SomeContextFactory(Configuration configuration)
    {
        _configuration = configuration;
    }

    public SomeContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<SomeContext>();

        optionsBuilder.UseSqlServer(_configuration.ConnectionString);

        return new SomeContext(optionsBuilder.Options);
    }
}

public class SomeContext : DbContext
{
    public DbSet<SomeDbModel> Some { get; set; }

    public SomeContext(DbContextOptions<SomeContext> options) : base(options)
    {
    }
}

The point is that the connection string is different depending on the environment (dev,test,prod), and migrations should be performed on the database specified by the Configuration.

How do instruct migrations to inject Configuration into SomeContextFactory?


Solution

  • By design, the IDesignTimeDbContextFactory isn't supposed to work with DI. One way to achieve this would be:

    public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
    {
      public AppDbContext CreateDbContext(params string[] args)
      {
        var options = new DbContextOptionsBuilder<AppDbContext>();
        var config = GetAppConfiguration();
        options.UseSqlServer(config.GetConnectionString("DesignTimeAppDbConnection"));
    
        return new AppDbContext(options.Options);
      }
    
      IConfiguration GetAppConfiguration()
      {
        var environmentName =
                  Environment.GetEnvironmentVariable(
                      "ASPNETCORE_ENVIRONMENT");
    
        var dir = Directory.GetParent(AppContext.BaseDirectory);      
    
        if(EnvironmentName.Development.Equals(environmentName, 
            StringComparison.OrdinalIgnoreCase))
        {                  
          var depth = 0;
          do
            dir = dir.Parent;
          while (++depth < 5 && dir.Name != "bin");
          dir = dir.Parent;
        }
    
        var path = dir.FullName;
    
        var builder = new ConfigurationBuilder()
                .SetBasePath(path)
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{environmentName}.json", true)
                .AddEnvironmentVariables();
    
        return builder.Build();
      }
    }