.Net Core DI 将运行时参数传递到服务的构造函数中,并将其传递给其子服务的 1-n 个子服务



我有多个流程服务。这些服务有一个属性,我需要在使用特定服务之前填写该属性。然而,这些流程服务也使用1-n生成器子服务,它们也具有与流程服务相同的属性。

public interface IProcess
{
IEnumerable<string> metadata;
//...
}
public class Process1 : IProcess
{
public IEnumerable<string> Metadata {get; set;}
private readonly IGenerator1 Generator1;
private readonly IGenerator2 Generator2;
public Process1(
IGenerator1 generator1,
IGenerator2 generator2,
IEnumerable<string> metadata)
{
Generator1 = generator1;
Generator2 = generator2;
Metadata = metadata;
}
}
public interface IGenerator
{
IEnumerable<string> metadata;
//...
}
public class Generator1 : IGenerator
{
public IEnumerable<string> Metadata {get; set;}
private readonly ILogger Logger;
public Generator1(
ILogger logger,
IEnumerable<string> metadata)
{
Logger = logger;
Metadata = metadata;
}
}

我在ServiceBuilder 中使用DI并解决依赖关系

public class ServiceBuilder
{
public ServiceBuilder()
{
var services = new ServiceCollection();
services.AddTransient<IProcess, Process1>();
services.AddSingleton<IProcessFactory, ProcessFactory>();
services.AddTransient<IDeliverySiteGenerator, DeliverySiteGenerator>();
services.AddTransient<INewConnectionErrandGenerator, NewConnectionErrandGenerator>();
//...
ServiceProvider = services.BuildServiceProvider();
}
}

并使用ProcessFactory类及其方法GetProcess来检索我想要使用的进程。我在List<IProcess>中添加这些进程,然后使用此列表从所有检索到的IProcess服务中执行特定方法。CCD_ 2是由用户输入提供的,它还包括我们想要的属性CCD_。

public class ProcessFactory : IProcessFactory
{
private readonly IServiceProvider serviceProvider;
//...
public IProcess GetProcess(SomeConfigData configData)
{
var processExists = registeredProcesses.TryGetValue(configData, out var processType);
if (!processExists)
throw new InvalidArgumentException($"Process not supported.");
return (IProcess)serviceProvider.GetService(processType);
}
}

目前,我通过GetProcess方法检索Metadata后,将其添加到了IProcess服务中,而Metadata具有公共setter。但它并没有解决如何将其传递给生成器子服务的问题。不想遍历流程服务的所有生成器实例,并通过公共setter添加Metadata。有什么办法可以做到这一点吗?

一种方法是创建一个作用域服务来提供对元数据的访问:

public interface IMetadataAccessor
{
IEnumerable<string> Metadata { get; set; }
}
public class MetadataProcessor : IMetadataAccessor
{
public IEnumerable<string> Metadata { get; set; }
}

将服务注册为作用域:

serviceCollection.AddScoped<IMetadataAccessor, MetadataProcessor>();

将进程和生成器类更改为通过构造函数注入IMetadataAccessor,并读取如下元数据:

public IEnumerable<string> Metadata => _metadataAccessor.Metadata;

更改工厂以实例化范围内的流程:

public Processor CreateProcessor(IEnumerable<string> metadata)
{
// Resolve services within a child scope
using (var scope = _services.CreateScope())
{
// Resolve the accessor service and set metadata
var accessor = scope.ServiceProvider.GetRequiredService<IMetadataAccessor>();
accessor.Metadata = metadata;
// Within the current scope, there is only one IMetadataAccessor.
// So both process and generator will be getting same accessor instance via the constructor.
// If we set metadata to the instance, all services can get the value.
var process = scope.ServiceProvider.GetRequiredService<Process>();
return process;
}
}

最新更新