【问题标题】:.Net Core DI pass runtime parameter into constructor of service and also into 1-n of its' subservices.Net Core DI 将运行时参数传递给服务的构造函数,也传递给它的 1-n 个子服务
【发布时间】:2020-04-03 08:15:23
【问题描述】:

我有多个流程服务。这些服务有一个属性,我需要在使用特定服务之前填写它。然而,这些流程服务也使用 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;
    }
}

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

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&lt;IProcess&gt; 中,然后使用此列表从所有检索到的 IProcess 服务中执行特定方法。 configData 由用户输入提供,它还包括我们想要的属性IEnumerable&lt;string&gt; Metadata

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 具有公共设置器。但它并没有解决如何将其传递给生成器子服务的问题。不想遍历流程服务的所有生成器实例并通过公共设置器添加Metadata。有什么方法可以实现吗?

【问题讨论】:

    标签: c# .net-core dependency-injection constructor parameter-passing


    【解决方案1】:

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

    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-05-21
      • 1970-01-01
      • 2013-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多