Autofa c ResolvedParameter / ComponentContext не работает - PullRequest
1 голос
/ 08 мая 2020

Я использую asp.net core вместе с Entity Framework Core. Мой сценарий здесь таков: я хочу изменить строку подключения во время выполнения на основе значения HttpContext строки запроса.

Я пытаюсь передать ResolvedParameter с Reflection components как задокументировано . Но, когда я разрешаю это, он не регистрируется. Ниже я прикрепил свой фрагмент кода.

Autofa c Класс регистрации:

public class DependencyRegistrar : IDependencyRegistrar
{
    public virtual void Register(ContainerBuilder builder)
    {
        builder.RegisterType(typeof(DbContextOptionsFactory))
            .As(typeof(IDbContextOptionsFactory))
            .InstancePerRequest();

        builder.RegisterType<AppDbContext>()
            .As(typeof(IDbContext))
            .WithParameter(
                new ResolvedParameter(
                    (pi, cc) => pi.Name == "options",
                    (pi, cc) => cc.Resolve<IDbContextOptionsFactory>().Get()));

        builder.RegisterGeneric(typeof(Repository<>))
            .As(typeof(IRepository<>))
            .SingleInstance();
    }
}

public interface IDbContextOptionsFactory
{
    DbContextOptions<AppDbContext> Get();
}

public class DbContextOptionsFactory : IDbContextOptionsFactory
{
    public DbContextOptions<AppDbContext> Get()
    {
        try
        {
            IConfigurationRoot configuration = new ConfigurationBuilder()
                                            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                                            .AddJsonFile("appsettings.json")
                                            .Build();

            var builder = new DbContextOptionsBuilder<AppDbContext>();

            if (EngineContext.Current.Resolve<IHttpContextAccessor>().HttpContext.Request.QueryString.ToString().ToLower().Contains("app1"))
                DbContextConfigurer.Configure(builder, configuration.GetConnectionString("app1"));
            else if (EngineContext.Current.Resolve<IHttpContextAccessor>().HttpContext.Request.QueryString.ToString().ToLower().Contains("app2"))
                DbContextConfigurer.Configure(builder, configuration.GetConnectionString("app2"));

            return builder.Options;
        }
        catch (Exception)
        {
            throw;
        }
    }
}

public class DbContextConfigurer
{
    public static void Configure(DbContextOptionsBuilder<AppDbContext> builder, string connectionString)
    {
        builder.UseSqlServer(connectionString);
    }
}

AppDbContext:

public class AppDbContext : DbContext, IDbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {

    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        Assembly assemblyWithConfigurations = typeof(IDbContext).Assembly;
        builder.ApplyConfigurationsFromAssembly(assemblyWithConfigurations);
    }

    //..
    //..
}

Во время выполнения я получаю ошибку ниже.

Произошло необработанное исключение при обработке запроса.

DependencyResolutionException: ни один из конструкторов, найденных с 'Autofa c .Core.Activators.Reflection.DefaultConstructorFinder 'для типа' AppDbContext 'может быть вызван с доступными службами и параметрами: Невозможно разрешить параметр' Microsoft.EntityFrameworkCore.DbContextOptions 1[AppDbContext] options' of constructor 'Void .ctor(Microsoft.EntityFrameworkCore.DbContextOptions 1 [AppDbContext]) ». Autofa c .Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings (ConstructorInfo [] availableConstructors, контекст IComponentContext, параметры IEnumerable)

Я пробовал, поскольку ответил здесь .. но , не работает.

1 Ответ

1 голос
/ 08 мая 2020

Я решил эту проблему, изменив комментарий Гуру Строна и последующие изменения. Вот мои изменения.

Шаг 1: Изменен Autofa c Класс регистрации, как показано ниже:

public class DependencyRegistrar : IDependencyRegistrar
{
    public virtual void Register(ContainerBuilder builder)
    {
        //Removed this code
        //builder.RegisterType(typeof(DbContextOptionsFactory))
        //    .As(typeof(IDbContextOptionsFactory))
        //    .InstancePerRequest();

        //Added this code
        builder.Register(c => c.Resolve<IDbContextOptionsFactory>().Get())
            .InstancePerDependency();  // <-- Changed this line

        builder.RegisterType<AppDbContext>()
            .As(typeof(IDbContext))
            .WithParameter(
                new ResolvedParameter(
                    (pi, cc) => pi.Name == "options",
                    (pi, cc) => cc.Resolve<IDbContextOptionsFactory>().Get()))
            .InstancePerDependency();  // <-- Added this line

        builder.RegisterGeneric(typeof(Repository<>))
            .As(typeof(IRepository<>))
            .InstancePerDependency();  // <-- Changed this line
    }
}

Теперь, если вы получаете сообщение об ошибке:

InvalidOperationException: для этого DbContext не настроен поставщик базы данных. Поставщика можно настроить, переопределив метод DbContext.OnConfiguring или используя AddDbContext в поставщике службы приложения. Если используется AddDbContext, также убедитесь, что ваш тип DbContext принимает объект DbContextOptions в своем конструкторе и передает его в базовый конструктор для DbContext.

Путем добавления кода ниже в классе AppDbContext для разрешения выше ошибка.

Шаг 2: Изменено AppDbContext (Добавлен метод OnConfiguring())

public class AppDbContext : DbContext, IDbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {

    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        Assembly assemblyWithConfigurations = typeof(IDbContext).Assembly;
        builder.ApplyConfigurationsFromAssembly(assemblyWithConfigurations);
    }

    //Added this method
    protected override void OnConfiguring(DbContextOptionsBuilder dbContextOptionsBuilder)
    {
        base.OnConfiguring(dbContextOptionsBuilder);
    }

    //..
    //..
}
...