Использование разных реализаций для одного интерфейса в Autofac
Я хочу сделать следующее.
Я реализовал планировщик с 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 ответ
Кажется, ты почти понял это. Я не знаю, как именно выглядят ваши классы, поэтому я составил пример с некоторой реализацией заглушки для 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
за область действия с внедрением свойства, которое будет настроено позже при создании области действия. Я сделал внедренные экземпляры доступными через общедоступные свойства. Просто для простого тестирования примера. Надеюсь, поможет.