Как динамически изменить изменение DI с помощью autofac? - PullRequest
0 голосов
/ 08 июня 2018

Мы разрабатываем службу Windows, и я хочу динамически изменить класс dbcontext в репозиториях.

Ниже приведен сценарий.

У меня есть три класса контекста БД

 public abstract class Context : DbContext, IUnitOfWork
    {
        protected Context(string connectionString) : base(connectionString)
        {

        }
    }

    public class PlatformContext : Context
    {
        private readonly string _connectionString;

        public PlatformContext(string connectionString)
            : base(connectionString)
        {
            _connectionString = connectionString;
        }
    }

    public class PlatformReplicaContext : Context
    {
        private readonly string _connectionString;
        public PlatformReplicaContext(string connectionString)
            : base(connectionString)
        {
            _connectionString = connectionString;
        }
    }

    public class TempContext : Context
    {
         private readonly string _connectionString;
         public TempContext(string connectionString)
        : base(connectionString)
         {
           _connectionString = connectionString;
         }
   }

и у меня есть репозиторий

public interface ICategoryRepository : IRepository<Category>
   {

   }

 public class CategoryRepository :Repository<Category>, ICategoryRepository
   {
        public CategoryRepository(Context context) : base(context)
        {

        }
   }

поэтому я использую CQRS, у меня есть еще три класса

public class CategoryBasicQuery:IRequest<BaseQueryResponse>
{
    public int CategoryId { get; set; }
}

public class CategoryBasicQueryHandler : IRequestHandler<CategoryBasicQuery, BaseQueryResponse>
{
    private readonly ICategoryRepository _categoryRepository;
    private readonly IMapper _mapper;

    public CategoryBasicQueryHandler(ICategoryRepository categoryRepository, IMapper mapper)
    {
        _categoryRepository = categoryRepository;
        _mapper = mapper;
    }
    public async Task<BaseQueryResponse> Handle(CategoryBasicQuery request, CancellationToken cancellationToken)
    {
        var entry = await _categoryRepository.FindAsync(request.CategoryId);
        if (entry == null)
        {
            return new NotFoundResponse();
        }

        var response = _mapper.Map<CategoryBasicResponse>(entry);
        return response;
    }
}

Теперь вот проблема

Здесь репозиторий категории долженуметь выполнять запросы во всех 3 типах контекстов.но как я должен зарегистрировать классы с использованием autofac?затем я пришел к решению, генерирующему репозитории во время выполнения, как показано ниже:

public class RepositoryFactory
{
    public static TRepository GetRepositoryInstance<T, TRepository>(
        params object[] args)
        where TRepository : IRepository<T>
    {
        return (TRepository)Activator.CreateInstance(typeof(TRepository), args);
    }
}

я вызываю этот метод внутри CategoryBasicQueryHandler класса, как этот

 var categoryRepo = RepositoryFactory.GetRepositoryInstance<Category, CategoryRepository>(new PlatformReplicaContext("connectionString"));

, но при вызове из CQRS

var categoty = new Category();
var command = new CategoryBasicQuery {CategoryId = categoryId};
var result =  _mediator.Send(command);

VS выдайте мне следующую ошибку

enter image description here

и мою регистрацию автофака следующим образом

    builder.RegisterType<CategoryService>().AsSelf();
    builder.RegisterType<ActionRepository>().As<IActionRepository>();
    builder.RegisterType<CategoryRepository>().As<ICategoryRepository>();
    builder.RegisterType<Mapper>().As<IMapper>();

может кто угоднопомогите мне решить эту проблему или предложите хороший способ справиться с этой ситуацией.

спасибо.

1 Ответ

0 голосов
/ 18 июня 2018

Это может дать вам хорошую отправную точку для возможного решения: http://autofaccn.readthedocs.io/en/latest/resolve/relationships.html#keyed-service-lookup-iindex-x-b

builder.RegisterType<PlatformContext>().Keyed<Context>("platform");
builder.RegisterType<PlatformReplicaContext>().Keyed<Context>("replica");
builder.RegisterType<TempContext>().Keyed<Context>("temp");

Вы упомянули в комментарии, что где-то есть переменная с именем action, которая будет указывать, какую реализацию использовать:

public class Class1
{
    private readonly IIndex<string, Context> contexts;

    public Class1(IIndex<string, Context> contexts)
    {
         this.contexts = contexts;
    }

    public void Whatever()
    {
        string action = ...; // platform, replica or temp
        Context context = this.contexts[action];
        ...
    }
}

Конечно, это нужно адаптировать так, чтобы оно вписывалось в остальную часть вашего приложения.Возможный пример может быть:

Context context = this.contexts[action];

using(ILifetimeScope scope = container.BeginLifetimeScope(builder =>
{
    builder.RegisterInstance(context).As<Context>();
}))
{
    // Because we are resolving IMediator from the scope, the selected Context will be used in all dependencies
    var mediator = scope.Resolve<IMediator>();
    mediator.Send(...);
}
...