C# 在ASP.NET核心依赖项注入中使用工厂模式
我需要ASP.Net核心依赖项注入来将一些参数传递给实现ICardPaymentRepository接口的GlobalRepository类的构造函数 这些参数用于配置,来自配置文件和数据库,我不希望我的类去引用数据库和配置本身 我认为工厂模式是实现这一点的最佳方式,但我无法找到使用工厂类的最佳方式,因为工厂类本身依赖于配置和数据库 我的启动目前看起来是这样的:C# 在ASP.NET核心依赖项注入中使用工厂模式,c#,asp.net-core,dependency-injection,.net-core,C#,Asp.net Core,Dependency Injection,.net Core,我需要ASP.Net核心依赖项注入来将一些参数传递给实现ICardPaymentRepository接口的GlobalRepository类的构造函数 这些参数用于配置,来自配置文件和数据库,我不希望我的类去引用数据库和配置本身 我认为工厂模式是实现这一点的最佳方式,但我无法找到使用工厂类的最佳方式,因为工厂类本身依赖于配置和数据库 我的启动目前看起来是这样的: public class Startup { public IConfiguration _configuration { g
public class Startup
{
public IConfiguration _configuration { get; }
public IHostingEnvironment _environment { get; }
public Startup(IConfiguration configuration, IHostingEnvironment environment)
{
_configuration = configuration;
_environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IDbRepository, DbRepository>();
var connection = _configuration.GetConnectionString("DbConnection");
services.Configure<ConnectionStrings>(_configuration.GetSection("ConnectionStrings"));
services.AddDbContext<DbContext>(options => options.UseSqlServer(connection));
services.AddScoped<ICardPaymentRepository, GlobalRepository>();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IRFDbRepository rFDbRepository)
{
...
}
}
现在如何从启动时将模式从配置和apiKey从DbRepository传递到构造函数?注册存储库时使用factory委托重载
//...
string mode = "get value from config";
services.AddScoped<ICardPaymentRepository, GlobalRepository>(sp => {
IDbRepository repo = sp.GetRequiredService<IDbRepository>();
string apiKey = repo.GetApiKeyMethodHere();
return new GlobalRepository(mode, apiKey);
});
//...
您可能还想检查这些链接 关于最后一个环节,代码基本上是:
public class Factory<T> : IFactory<T>
{
private readonly Func<T> _initFunc;
public Factory(Func<T> initFunc)
{
_initFunc = initFunc;
}
public T Create()
{
return _initFunc();
}
}
public static class ServiceCollectionExtensions
{
public static void AddFactory<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
services.AddTransient<TService, TImplementation>();
services.AddSingleton<Func<TService>>(x => () => x.GetService<TService>());
services.AddSingleton<IFactory<TService>, Factory<TService>>();
}
}
我遇到了同样的问题,并通过为
IFactory
、IFactory
、IFactory
等注册一组开放泛型解决了这个问题。启动时只需调用一次就可以添加此功能,然后允许注入/解决任何IFactory
,它将为给定的一组参数类型实例化T服务
的实例,前提是存在一个构造函数,其最后参数与工厂泛型的T*
类型匹配。源代码、NuGet软件包和解释性博客文章如下:
其他答案的替代方案。遵循规则 首先为您的配置引入强类型
公共类响应选项{
公共字符串模式{get;set;}
公共字符串ApiKey{get;set;}
}
公共全局存储库(IOPS选项){
//使用选项。价值;
}
如果愿意,您仍然可以使用服务工厂方法打开IOptions
。但是,您将无法验证您的服务依赖项是否已全部满足
然后你可以从配置中选择种子
public void配置服务(IServiceCollection服务){
...
services.Configure(_configuration.GetSection(name));
...
}
并编写另一个服务来从其他服务(如数据库)更新该选项实例
公共类配置位置选项:IConfigureOptions{
私有只读存储库回购;
公共配置位置选项(IDbRepository repo){
this.repo=回购;
}
公共void配置(RespositoryOptions配置){
字符串apiKey=repo.GetApiKeyMethodHere();
}
}
在注册存储库时使用factory委托重载另外,如果GlobalRepository需要其他服务,那么我只需使用sp.GetService手动将它们传递进来?此用法的参考:您不能这样做吗:?Bill,如果您不需要分离接口(TService),您的要点会更简单(因此更好)从一个实现(TImplementation)开始。当您打算使用工厂生成一个不包含太多实现代码的类(例如DAO)时,您的要点将非常合适。谢谢你的评论。
//...
string mode = "get value from config";
services.AddScoped<ICardPaymentRepository>(sp => {
IDbRepository repo = sp.GetRequiredService<IDbRepository>();
string apiKey = repo.GetApiKeyMethodHere();
return ActivatorUtilities.CreateInstance<GlobalRepository>(sp, mode, apiKey);
});
//...
public class Factory<T> : IFactory<T>
{
private readonly Func<T> _initFunc;
public Factory(Func<T> initFunc)
{
_initFunc = initFunc;
}
public T Create()
{
return _initFunc();
}
}
public static class ServiceCollectionExtensions
{
public static void AddFactory<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
services.AddTransient<TService, TImplementation>();
services.AddSingleton<Func<TService>>(x => () => x.GetService<TService>());
services.AddSingleton<IFactory<TService>, Factory<TService>>();
}
}
public class DefaultFooFactory: IFooFactory{
public IFoo create(){return new DefaultFoo();}
}