基于配置文件的具有不同参数的 class 的多个实例

Multiple instances of class with different parameters based on configuration file

所以我有一个简单的配置class PubsubSettings:

public class PubSubSettings
{
  public string ProjectId { get; set; }
  public string TopicId { get; set; }
  public int PartnerId { get; set; }
  public string SubscriptionId { get; set; }
}

我以前只在我的 appsettings.json 中配置了其中一个,但现在我希望能够处理任意数量的它们。

我还有一个 class、PubSub,我通常会在其中注入一个 IOptions<PubSubSettings>。而这又被注入到我的 Worker class.

services.Configure<PubSubSettings>(configuration.GetSection(nameof(PubSubSettings)));
...
services.AddHostedService<Worker>();

所以,我现在要做的是为我的 AppSettings PubSubSettings 部分中的每个条目添加一个新的 Worker 作为托管服务,并将相关的 IOptions<PubSubSettings> 注入每个其中(连同标准 ILogger)。

所以本质上,我想要这个配置块:

 "PubsubSettings": [
    {
      "ProjectId": "project1",
      "TopicId": "topic",
      "PartnerId": 1,
      "SubscriptionId": "sub1"
    },
    {
      "ProjectId": "project2",
      "TopicId": "topic2",
      "PartnerId": 2,
      "SubscriptionId": "sub2"
    }    
  ]

最终创建两个托管服务,一个使用第一组选项,另一个使用第二组。

我已经看到一些问题在寻找类似的东西,但我找不到与此完全一致的东西,所以我有点难过。有什么想法吗?

解决方案是 Dotnet 5。

也许你可以尝试只为对象创建一个 class 并让 PubSubSettings class 只为数组:

public class PubSubSettings
{
  public PubSubObject[] PubSubs { get; set; }
}

public class PubSubObject
{
  public string ProjectId { get; set; }
  public string TopicId { get; set; }
  public int PartnerId { get; set; }
  public string SubscriptionId { get; set; }
}

然后在启动时class你应该使用Bind获取数组的当前值来为每个PubSub创建一个Worker:

PubSubSettings settings = new PubSubSettings();
Configuration.GetSection(nameof(PubSubSettings)).Bind(settings);
...
foreach(PubSubObject item in settings.PubSubs)
{
   services.AddHostedService<Worker>();
}

然后在PubSub class中你需要搜索Array里面的PartnerId

或者您可以按照 Microsoft 文档中命名选项支持使用 IConfigureNamedOptions 部分中描述的方法:Options pattern in ASP.NET Core

因此,根据我所能找到的,没有任何开箱即用的方法。

但是,这可以使用 ActivatorUtilitiesConfiguration.Bind() 的组合手动完成。

private void CreateWorkers(IServiceCollection services, IConfigurationRoot configuration)
{
    List<PubSubSettings> pubsubSettings = new();
    configuration.Bind(nameof(PubSubSettings), pubsubSettings);
    
    foreach (PubSubSettings setting in pubsubSettings)
    {
        services.AddSingleton<IHostedService>(s => ActivatorUtilities.CreateInstance<Worker>(s, ActivatorUtilities.CreateInstance<PubSub.PubSub>(s, setting)));
    }
}

本质上,您可以使用Bind 从JSON 中获取配置对象。然后您可以使用 CreateInstance.

手动构造 Worker 以调用 AddHostedService

在这种情况下需要两次调用,一次为 worker 生成 PubSub(我们在其中传递设置参数),另一次调用生成 Worker 本身。

ActivatorUtilities 本质上是注入对象所需的一切,除了您提供的参数。

我们需要使用 .AddSingleton<IHostedService> 因为 AddHostedService().