ASP.NET 核心创建类实例,其中类可以使用 DI - 寻找模式建议



我有一个问题,我需要用一些配置数据实例化一个类,但该类可能会使用它从 DI 容器收集的其他类。 我在Startup注册了许多服务,我可以毫无问题地从控制器和服务访问这些服务-运行良好。

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

该类需要一些配置数据(它们用于与外部系统通信(,我需要弄清楚如何传递配置数据以及允许 DI 适用于那些需要其他服务的类。

IProvider接口定义为:

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

使用它的类可能是这样的:

public class ProviderA: IProvider
{
private readonly SMSService _smsService;
public ProviderA(SMSService smsService, string configuration)
{
_smsService = smsService;
//do something with configuration
}
public Task<string> ValidateAsync()
{
//validate connection using passed in configuration
throw new NotImplementedException();
}
}

根据用户输入,我需要创建类的新实例,但希望类找出自己的依赖项(在这种情况下SMSService(。我还注意到SMSService可能还有其他依赖项(dbContext等(。

我创建新实例的代码是计算对象的类型并创建一个实例:

provider = new ProviderA(configuration);

关于如何创建此对象的实例、传入参数并允许它获取自己的依赖项的任何想法? 我怀疑我的方法不正确,但在过去,它运行良好,但现在有了 DI,它给我带来了麻烦,因为需要获取各种服务并且需要传递参数。

这是工厂模式的完美方案。你注入你的工厂,然后在运行时,你从中获得你需要的实际实例。例如:

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的东西在创建实例时存储实例。这在很大程度上取决于你和应用程序的需求。重点是拥有这个工厂类,您可以在其中提取所需的正确提供程序实例。注入那个工厂,你就可以走了。

我建议在界面中添加一些描述字段IProvider例如:

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

它允许您注入接口的所有实现,并根据用户输入选择其中一个:

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

至于配置,您可以为每种类型的提供程序创建 Config 类并注册它:

public class Config
{
public string SomeConfig { get; set; }
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(new Config());
}
public ProviderA(SMSService smsService, Config configuration)
{
}

或者甚至将配置放在appsettings.json中并使用IOptions模式

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

最新更新