简体   繁体   中英

Passing Services to custom IMigrationHistory implementation

Using PostgreSQL with ASP.NET Core 3.1. My Migration History table exists in its own schema as we have a multitenant setup with each tenant being associated with a separate schema. I am now trying to modify the Migration History table by adding new columns and putting custom values into those (like build number).

Now I am aware that I will have to re-create the schema in order for the new columns to be added on the initial migration.

But what I am failing in doing is to pass an instance of IConfiguration into my custom MigrationsHistory implementation (configuration contains the build number to be inserted into the custom BuildVersion column). This is the code I have on DBContext's OnConfiguring() method to replace IHistoryRepository with a custom one:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseNpgsql(
        _tenantConnectionString,
        npgsqlOptionsAction: npgsqlOptions =>
        {
            npgsqlOptions.EnableRetryOnFailure();
            npgsqlOptions.MigrationsHistoryTable("__EFMigrationsHistory", _tenantDbSchema);
        })
        .ReplaceService<IHistoryRepository, CustomHistoryRepository>(); 
}

Here is the code for my custom Migration History table:

public class CustomHistoryRepository : NpgsqlHistoryRepository
{
    private readonly IConfiguration _configuration;

    public CustomHistoryRepository (
        [NotNull] HistoryRepositoryDependencies dependencies,
        IConfiguration configuration) 
        : base(dependencies)
    {
        _configuration = configuration;
    }

    protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
    {
        base.ConfigureTable(history);
        history.Property<string>("BuildVersion")
            .HasDefaultValue(_configuration["BuildVersion"] ?? "Unknown");
    }
}

Now I am failing to inject IConfiguration when costructing CustomHistoryTable . It likely has to do with the fact that EF uses an internal ServiceProvider so I tried to inject my own but then I would have to configure all dependencies which is a lot. Is my suspicion regarding internal EF ServiceProvider correct and how can I resolve this problem?

This seems to solve the problem of providing your own ServiceProvider with minimal input and thus, in turn, exposing all services, including IConfiguration, to CustomHistoryProvider :

services.AddDbContext<ApplicationDbContext>(
    options => options
        .UseInternalServiceProvider(services
            .AddEntityFrameworkNpgsql()
            .AddEntityFrameworkProxies()
            .AddScoped<IHistoryRepository, CustomHistoryRepository>()
            .BuildServiceProvider())
        .UseLazyLoadingProxies()
        .EnableSensitiveDataLogging(enableSensitiveDataLogging));

Note that use of AddEntityFrameworkNpgsql() is specific to Npgsql provider for PostgreSQL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM