Search code examples
c#entity-framework.net-coresimple-injector

Inject DbContext to repository based on the generic type using Simple Injector


Consider I have the following generic class:

public class Repository<T> : IRepository<T> where T : class
{
    private DbContext Context { get; set; }

    public Repository(DbContext context)
    {
        Context = context;
    }
}

And I register two different dbcontext as below, using SimpleInjector :

container.Register<ContextA>(
    ()=> new ContextA(SqlServerDbContextOptionsExtensions.UseSqlServer(
        new DbContextOptionsBuilder(), sqlConnection).Options));

container.Register<ContextB>(
    () => new ContextB(SqlServerDbContextOptionsExtensions.UseSqlServer(
        new DbContextOptionsBuilder(), sqlConnection).Options));

And then I have the following registration for dbContext :

container.RegisterConditional(
    typeof(DbContext),
    typeof(ContextA),
    c=> c.Consumer.ImplementationType.GenericTypeArguments
        .Any(r => r.Namespace == "NameSpace.ContextA"));

container.RegisterConditional(
    typeof(DbContext),
    typeof(ContextB),
    c => c.Consumer.ImplementationType.GenericTypeArguments
        .Any(r => r.Namespace == "NameSpace.ContextB"));

When the codes reaches container.RegisterConditional it throws error and complains about a ContextA having two constructor.

Considering that I have already injected ContextA and ContextB, what is the best way to inject appropriate DbContext for Repository based on its generic argument value?

Update

I want to inject DbContext to Repository<T>, based on the type passed to initialize the Repository<T>.

So I might have:

IRepository<Entity1> ...

Which Entity1 could be in NameSpace.ContextA.


Solution

  • You need to use the RegisterConditional overload that accepts a Registration. This way you can wrap the lambda expression inside the Registration as follows:

    var contextARegistration =
        Lifestyle.Scoped.CreateRegistration(
            () => new ContextA(
                SqlServerDbContextOptionsExtensions.UseSqlServer(
                    new DbContextOptionsBuilder(), sqlConnection).Options),
            container);
    
    container.RegisterConditional(
        typeof(DbContext),
        contextARegistration,
        c => c.Consumer.ImplementationType.GenericTypeArguments
                 .Any(r => r.Namespace == "NameSpace.ContextA"));
    
    var contextBRegistration =
        Lifestyle.Scoped.CreateRegistration(
            () => new ContextB(
                SqlServerDbContextOptionsExtensions.UseSqlServer(
                    new DbContextOptionsBuilder(), sqlConnection).Options),
            container);
    
    container.RegisterConditional(
        typeof(DbContext),
        contextBRegistration,
        c => c.Consumer.ImplementationType.GenericTypeArguments
                 .Any(r => r.Namespace == "NameSpace.ContextB"));