Использование разных реализаций для одного интерфейса в Autofac - PullRequest
0 голосов
/ 12 сентября 2018

Я хочу сделать следующее.

Я реализовал планировщик с Quartz.Net и для IOC я использую Autofac. Теперь я хочу начать одну работу несколько раз, но база данных для каждой работы различна. Мой репозиторий принимает параметр, который оборачивает мою строку подключения. Параметр имеет тип IOptions<T> и вводится в конструктор хранилища. Хранилище также внедряется в разные сервисы.

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

Хранилище реализовано кем-то другим и содержит несколько запросов и одно свойство строки подключения. У меня есть разные базы данных для разных стран (системы продаж), но все они одинаковы, поэтому у меня есть только один репозиторий для всех баз данных.

Строки подключения считываются из файла JSON:

{
  "PriceListSettings": [
    {
      "Country": "DE",
      "ConnectionString": "Initial Catalog=Catalog_DE;Data Source=.\\SQLEXPRESS;Integrated Security=true;",
      "ExecutionTime": "0 0 0 1/1 * ? *"
    },
    {
      "Country": "AT",
      "ConnectionString": "Initial Catalog=Catalog_AT;Data Source=.\\SQLEXPRESS;Integrated Security=true;",
      "ExecutionTime": "0 0 0 1/1 * ? *"
    }
  ]
}

Я хочу иметь область действия для каждой работы, чтобы я мог внедрить или установить другую строку подключения.

С Quarz вы можете установить триггер. Проблема в том, что все задания запускаются в настраиваемое время и должны выполняться один раз за ночь. Но я точно не знаю, когда.

Я пытался использовать

using (var scope = Program.Container.BeginLifetimeScope())
{
    //Does not seem to work this way
    //var repo = scope.Resolve<IRepository>();
    //repo.PricelistServiceConfig = priceListConfig;            
}

Я также пытался запустить Quartz в одном потоке, но, похоже, я не могу правильно установить свойство моего репо.

Используемые каркасы:

  • .Net Framework 4.6 (невозможно обновить)
  • Autofac 4.8.1
  • Autofac.Extras.Quartz 4.2.0
  • Кварц 3.0.6

1 Ответ

0 голосов
/ 12 сентября 2018

Кажется, ты почти понял.Я не знаю, как именно выглядят ваши классы, поэтому я составил пример с некоторой реализацией заглушки для Job, Reposiroty и классов сервисов.Есть работа, которая получает две услуги в конструктор.Обе службы требуют наличия репозитория в качестве параметра для своих конструкторов:

[Test]
public void AutofacLifetimeScope()
{
    // Arrange
    var builder = new ContainerBuilder();
    builder.RegisterType<Job>();
    builder.RegisterType<AnotherService>();
    builder.RegisterType<SomeService>();
    builder.RegisterType<Repository>().InstancePerLifetimeScope().WithProperty(ResolvedParameter.ForKeyed<Option>("opt"));

    var container = builder.Build();

    // Act
    Job job1;
    var option1 = new Option {ConnectinString = "DE Connection"};
    using (var scope = container.BeginLifetimeScope(c => c.RegisterInstance(option1).Keyed<Option>("opt")))
    {
        job1 = scope.Resolve<Job>();
    }

    Job job2;
    var option2 = new Option { ConnectinString = "AT Connection" };
    using (var scope = container.BeginLifetimeScope(c => c.RegisterInstance(option2).Keyed<Option>("opt")))
    {
        job2 = scope.Resolve<Job>();
    }

    //Assert
    Assert.AreEqual(job1.SomeService.Repository.PriceListConfig, option1);
    Assert.AreEqual(job1.AnotherService.Repository.PriceListConfig, option1);

    Assert.AreEqual(job2.SomeService.Repository.PriceListConfig, option2);
    Assert.AreEqual(job2.AnotherService.Repository.PriceListConfig, option2);
}

public class Repository
{
    public Option PriceListConfig { get; set; }
}

public class Option
{
    public string ConnectinString { get; set; }
    public string Country { get; set; }
    public string ExecutionTime { get; set; }
}

public class Job
{
    public SomeService SomeService { get; }
    public AnotherService AnotherService { get; }

    public Job(SomeService someService, AnotherService anotherService)
    {
        SomeService = someService;
        AnotherService = anotherService;
    }
}

public class AnotherService
{
    public Repository Repository { get; }

    public AnotherService(Repository repository)
    {
        Repository = repository;
    }
}

public class SomeService
{
    public Repository Repository { get; }

    public SomeService(Repository repository)
    {
        Repository = repository;
    }
}

Основная идея состоит в том, чтобы зарегистрировать Repository на область действия времени жизни с введением свойства, которое будет настроено позже во время создания области действия времени жизни.Я сделал внедренные экземпляры доступными через общедоступные свойства.Просто для простого тестирования примера.Надеюсь, это поможет.

...