Using Factory Pattern with ASP.NET Core Dependency

2019-06-26 02:58发布

问题:

I need the ASP.Net Core dependency injection to pass some parameters to the constructor of my GlobalRepository class which implements the ICardPaymentRepository interface.

The parameters are for configuration and come from the config file and the database, and I don't want my class to go and reference the database and config itself.

I think the factory pattern is the best way to do this but I can't figure out the best way to use a factory class which itself has dependencies on config and database.

My startup looks like this currently:

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)
    {
     ...
    }
}

The GlobalRepository constructor looks like this:

public GlobalRepository(string mode, string apiKey)
{
}

How do I now pass the mode from configuration and the apiKey from the DbRepository into the constructor from Startup?

回答1:

Use the factory delegate overload when registering the repository

//...

var mode = "get value from config";

services.AddScoped<ICardPaymentRepository, GlobalRepository>(sp => {        
    var repo = sp.GetService<IDbRepository>();
    var apiKey = repo.GetApiKeyMethodHere();

    return new GlobalRepository(mode, apiKey);
});

//...


回答2:

You might want to also check these links...

https://github.com/Microsoft/AspNetCoreInjection.TypedFactories

https://espressocoder.com/2018/10/08/injecting-a-factory-service-in-asp-net-core/

With regard to the last link the code is basically:

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

I think castle windsor's typed factories dispose of all they created when they themselves are disposed (which may not be always the best idea), with these links you would probably have to consider if you are still expecting that behaviour. When I reconsidered why I wanted a factory I ended up just creating a simple factory wrapping new, such as:

public class DefaultFooFactory: IFooFactory{
  public IFoo create(){return new DefaultFoo();}
}