在 Autofac 中对一个接口使用不同的实现
Using different implementations for one interface in 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 运行 在单线程中,但似乎我无法正确设置我的 repo 的 属性。
使用的框架:
- .Net Framework 4.6(无法升级)
- Autofac 4.8.1
- Autofac.Extras.Quartz 4.2.0
- 石英 3.0.6
看来,你差不多明白了。我不知道你的 类 到底是什么样子,所以我用 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
,这将在稍后创建生命周期范围时共同配置。我通过 public 属性使注入的实例可用。仅用于示例的简单测试。希望对你有帮助。
我要执行以下操作。
我使用 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 运行 在单线程中,但似乎我无法正确设置我的 repo 的 属性。
使用的框架:
- .Net Framework 4.6(无法升级)
- Autofac 4.8.1
- Autofac.Extras.Quartz 4.2.0
- 石英 3.0.6
看来,你差不多明白了。我不知道你的 类 到底是什么样子,所以我用 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
,这将在稍后创建生命周期范围时共同配置。我通过 public 属性使注入的实例可用。仅用于示例的简单测试。希望对你有帮助。