2

I got lost while building generic repository with entity framework which has multiple contexts in my asp.net core 2 api project.

What I need is to inject my repository to controller without knowing which context it is using.

DbContext

public interface IDbContext
{
}

public interface IBlogContext : IDbContext
{
}

public interface IBlogLogContext : IDbContext
{
}

Repository

public class EfRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
    private readonly IDbContext _context;
    private readonly DbSet<TEntity> _dbSet;

    public EfRepository(IDbContext context)
    {
        _context = context;
        _dbSet = _context.Set<TEntity>();
    }
    /* other stuff */
}     

Startup

public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<BlogContext>(options =>
        {

options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
            .UseLoggerFactory(_logger);
        });
        services.AddDbContext<BlogLogContext>(options =>
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
        });
        services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));

        services.AddScoped<IBlogContext, BlogContext>();
        services.AddScoped<IBlogLogContext, BlogLogContext>();

        services.AddUnitOfWork<BlogContext, BlogLogContext>();

    }

Controller

public class UserController : Controller
{
    private readonly IRepository<User> _repository;
    private readonly IAuthorService _authorService;
    private readonly ILogger<UserController> _logger;

    public UserController(IRepository<User> repository, IAuthorService authorService, ILogger<UserController> logger)
    {
        _repository = repository;
        _authorService = authorService;
        _logger = logger;
    }
}

When I inject IRepository<User> in controller constructor, how .net core DI resolve that User is BlogContext's entity, so IDbContext should be BlogContext inside my EfRepository implementation?

3
  • I seem to hear Walter Sobchak "You are entering a world of pain" Commented Sep 6, 2018 at 10:22
  • 1
    Personal opinion: repository pattern won't give you much with EF, except more work. Commented Sep 6, 2018 at 11:13
  • 1
    stackoverflow.com/a/51781877/5779732 Commented Sep 7, 2018 at 13:00

1 Answer 1

4

I defined my EfRepository with a DbContext generic argument like this:

 public class EfRepository<TDbContext, TEntity> : IRepository<TEntity>
    where TDbContext : DbContext
    where TEntity : class, IEntity
{
    public EfRepository(IDbContextProvider<TDbContext> dbContextProvider)
    {
    }
}

And got DbContext-Entity info like this:

//EntityTypeInfo is a class has EntityType & DeclaringType props
private IList<EntityTypeInfo> GetEntityTypeInfos()
{
    var result = new List<EntityTypeInfo>();
    var dbContextTypes = this.GetType().Assembly.GetTypes().Where(t => (typeof(DbContext).IsAssignableFrom(t)));
    foreach (var dbContextType in dbContextTypes)
    {
        result.AddRange(
            from property in dbContextType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
            where
                Common.IsAssignableToGenericType(property.PropertyType, typeof(DbSet<>)) &&
                Common.IsAssignableToGenericType(property.PropertyType.GenericTypeArguments[0], typeof(IEntity))
            select new EntityTypeInfo(
                property.PropertyType.GenericTypeArguments[0],
                property.DeclaringType
                );
    }
    return result;
}

So I can add relevant services with EntityTypeInfo list:

var entityTypeInfos = GetEntityTypeInfos();
foreach (var entityTypeInfo in entityTypeInfos)
{
    //
    //Add IDbContextProvider and DbContext services Here
    //

    //Add IRepository services like this
    var repositoryInterface =typeof(IRepository<>);
    var repositoryImplementation =typeof(EfRepository<,>);

    var genericRepositoryType = repositoryInterface.MakeGenericType(entityTypeInfo.EntityType);
    if (!Common.IocHasRegister(genericRepositoryType))
    {
        var implRepositoryType = repositoryImplementation.MakeGenericType(entityTypeInfo.DeclaringType, entityTypeInfo.EntityType);

        services.AddScoped(genericRepositoryType, implRepositoryType);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.