C# NET核心创建类实例,其中类可以使用DI查找模式建议

C# NET核心创建类实例,其中类可以使用DI查找模式建议,c#,asp.net-core,.net-core,C#,Asp.net Core,.net Core,我有一个问题,我需要用一些配置数据实例化一个类,但该类可能使用它从DI容器收集的其他类。 我在Startup中注册了许多服务,我可以从控制器和服务访问这些服务,而不会出现任何问题-工作正常 问题是我有一个接口,IProvider,它有许多实现它的类ProviderA,ProviderB等等。在运行时,根据用户的选择,我需要创建其中一个类的实例,并对其调用一些方法 该类需要一些配置数据(它们用于与外部系统通信),我需要解决如何传递配置数据以及如何允许DI为那些需要其他服务的类工作 IProvide

我有一个问题,我需要用一些配置数据实例化一个类,但该类可能使用它从DI容器收集的其他类。 我在
Startup
中注册了许多服务,我可以从控制器和服务访问这些服务,而不会出现任何问题-工作正常

问题是我有一个接口,
IProvider
,它有许多实现它的类
ProviderA
ProviderB
等等。在运行时,根据用户的选择,我需要创建其中一个类的实例,并对其调用一些方法

该类需要一些配置数据(它们用于与外部系统通信),我需要解决如何传递配置数据以及如何允许DI为那些需要其他服务的类工作

IProvider
接口定义为:

public interface IProvider
{
    Task<string> ValidateAsync();
}

关于如何创建此对象的实例、传入参数并允许其获得自己的依赖项,有什么想法吗?我怀疑我的方法是不正确的,但在过去,它工作得很好,但现在使用DI,它给我带来了麻烦,因为各种服务需要来源,参数需要传递。

我建议在
IProvider
接口中添加一些描述字段,例如:

public interface IProvider
{
    Task<string> ValidateAsync();

    ProviderType Type { get; }
}
甚至可以将配置放在appsettings.json中并使用

public void配置服务(IServiceCollection服务)
{
var section=Configuration.GetSection(“ProviderA”);
服务。配置(部分);
}
并消费它:

public ProviderA(SMSService smsService, IOptions<Config> configuration)
{
    var config = configuration.Value;
}
public ProviderA(SMSService SMSService,IOPS配置)
{
var config=configuration.Value;
}

这是工厂模式的完美场景。您注入工厂,然后在运行时从中获得所需的实际实例。例如:

public class ProviderFactory
{
    public ProviderFactory(...) { ... } // Inject all the stuff you need here

    public IProvider CreateProvider(string type)
    {
        // switch on `type`, new up the right provider, and return it
    }
}

当然,在这里你还可以做其他事情。您可能希望在构建过程中一次更新所有提供程序,或者您可以使用类似于
Lazy
的方法仅在访问它们时才更新它们。或者,您可以在创建实例时使用类似于
ConccurrentDictionary
的工具来存储实例。这在很大程度上取决于您和应用程序的需要。主要的一点是使用这个工厂类,您可以从中提取所需的正确的提供程序实例。注入那个工厂,你就可以走了。

这很有效。我已经根据您的样品创建了ProviderFactory,它运行良好。以前,我使用静态助手做很多相同的事情,但是通过工厂,我能够注入各种提供者所需的任何服务。他工作得很好。谢谢。谢谢Alex,我本来是这样做的,但是在配置上遇到了同样的问题。在本例中,它来自数据库,并且变化很大,因此IOptions模式并不真正合适。使用工厂概念进行排序。
public class MyService
{
    private IEnumerable<IProvider> providers;

    public MyService(IEnumerable<IProvider> providers)
    {
        this.providers = providers;
    }

    public Task Action(UserInput input)
    {
        var provider = providers.FirstOrDefault(el => el.Type == SmsProvider);
    }
}
public class Config
{
    public string SomeConfig { get; set; }
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(new Config());
}

public ProviderA(SMSService smsService, Config configuration)
{

}
public void ConfigureServices(IServiceCollection services)
{
    var section = Configuration.GetSection("ProviderA");
    services.Configure<Config>(section);
}
public ProviderA(SMSService smsService, IOptions<Config> configuration)
{
    var config = configuration.Value;
}
public class ProviderFactory
{
    public ProviderFactory(...) { ... } // Inject all the stuff you need here

    public IProvider CreateProvider(string type)
    {
        // switch on `type`, new up the right provider, and return it
    }
}