C# 在ASP.NET核心依赖项注入中使用工厂模式

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

我需要ASP.Net核心依赖项注入来将一些参数传递给实现ICardPaymentRepository接口的GlobalRepository类的构造函数

这些参数用于配置,来自配置文件和数据库,我不希望我的类去引用数据库和配置本身

我认为工厂模式是实现这一点的最佳方式,但我无法找到使用工厂类的最佳方式,因为工厂类本身依赖于配置和数据库

我的启动目前看起来是这样的:

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