在 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 的 属性。

使用的框架:

看来,你差不多明白了。我不知道你的 类 到底是什么样子,所以我用 JobReposiroty 和服务 类 的一些存根实现编写了一个示例。有一项工作将两项服务接收到构造函数中。这两项服务都需要存储库作为其构造函数的参数:

[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 属性使注入的实例可用。仅用于示例的简单测试。希望对你有帮助。