1

My goal is to create an object that contains different implementations of an interface and at runtime select the implementation to use. I'm using the Dependency injection in ASP.NET Core.

Code:

public interface IStateRepository : IDbReadRepository<IState> { }

public interface IDbReadRepository<T> : IBaseRepository
{
     IReadOnlyList<T> GetAll();
}

public interface IBaseRepository
{
    IUserContext UserContext { get; set; }
}

namespace MvcOpinionatedTemplate.Repositories.Dapper
{
    public class StateRepository : BaseDbRepository, IStateRepository
    {
        public StateRepository(IUserContext userContext, IDbConnection dbConnection) : base(userContext, dbConnection) { }

        public IReadOnlyList<IState> GetAll()
        {
            return _dbConnection.Query<State>("SELECT * FROM State").ToList();
        }
    }
}

namespace Template.Repositories.Local
{
    public class StateRepository : BaseRepository, IStateRepository
    {
        public StateRepository(IUserContext userContext) : base(userContext) { }

        public IReadOnlyList<IState> GetAll()
        {
            var filePath = Path.Combine(AppContext.BaseDirectory, @"Local\json\states.json");

            return JsonConvert.DeserializeObject<List<State>>(File.ReadAllText(filePath));
        }
}


namespace MvcOpinionatedTemplate.Repositories.Collections
{
    public class StateRepositories
    {
        public IStateRepository Local { get; }

        public IStateRepository SqlServer { get; }

        public StateRepositories(IStateRepository local, IStateRepository sqlServer)
        {
            Local = local;
            SqlServer = sqlServer;
        }
    }
}

What I'd like to do is set in the Startup.ConfigureServices():

services.AddTransient<StateRepositories, XXXXX>

I tried this:

services.AddTransient<StateRepositories>(s => new StateRepositories(new Repositories.Local.StateRepository(--UserContext--), new Repositories.Dapper.StateRepository(-UserContext--)));

The problem is how to have DI populate UserContext. I have it defined Startup.ConfigureServices():

services.AddScoped<IUserContext, UserContext>();

How do have DI populate UserContext for the StateRepositories implementations? Or is there a better approach to achieve my goal?

Josh
  • 8,219
  • 13
  • 76
  • 123
  • Possible duplicate of [Injecting multiple implementations with Dependency injection](https://stackoverflow.com/questions/40946320/injecting-multiple-implementations-with-dependency-injection) – Camilo Terevinto Jul 20 '18 at 23:06

1 Answers1

4

You can register your IStateRepository separately and then inject IEnumerable<IStateRepository> which injects all implementations of IStateRepository.

public interface IStateRepository
{
}

public class LocalRepository : IStateRepository
{
}

public class DapperRepository : IStateRepository
{
}

services.AddTransient<IStateRepository, LocalRepository>()
        .AddTransient<IStateRepository, DapperRepository>()
        .AddTransient<StateRepositories>();

public class StateRepositories
{
    public IStateRepository Local { get; }

    public IStateRepository SqlServer { get; }

    public StateRepositories(IEnumerable<IStateRepository> repositories)
    {
        Local = repositories.OfType<LocalRepository>().FirstOrDefault();
        SqlServer = repositories.OfType<DapperRepository>().FirstOrDefault();
    }
}
Kahbazi
  • 14,331
  • 3
  • 45
  • 76