Entity framework 6 dynamic connections string using DI

.net-4.6 connection-string dependency-injection entity-framework-6 unit-of-work

Question

I have a unit of work with the repository pattern with simple injector implemented and I need to change my connection string dynamically. Currently the connection string is taken from the web config. I need the connection string be taken from the database.

So I will have a database with the ASP.Net Identity and the connections strings (and other configurations needed for my application) and then a database depending on the client.

My repositories and Unit of work are as follows.

public abstract class DataRepositoryBase<TEntity, TContext> : IDataRepository<TEntity>
    where TEntity : class, IObjectStateEntity, new()
    where TContext : class, IDbSimpleContextAsync
    {
        protected DataRepositoryBase(TContext context)
        {
            Context = context;            
        }

        public virtual TContext Context { get; }

        public IEnumerable<TEntity> Get()
        {
            return Context.Get<TEntity>();
        }

        public TEntity Get(object id)
        {
            return Context.Find<TEntity>(id);
        }
}

public class SomeRepository : DataRepositoryBase<SomeObject, IContext>, ISomeRepository
{
    public SomeRepository (IContext context) : base(context)
    {
    }
}

public abstract class UnitOfWorkBase : IUnitOfWork
{
    private IDbSimpleContextAsync _dbContext;

    protected UnitOfWorkBase(IDbSimpleContextAsync dbContext)
    {
        _dbContext = dbContext;
    }

    public int SaveChanges()
    {
        return _dbContext.SaveChanges();
    }

    public Task<int> SaveChangesAsync()
    {
        return _dbContext.SaveChangesAsync();
    }
}

public class UnitOfWork : UnitOfWorkBase, IUnitOfWork
{
    private ISomeRepository _someRepository
    private readonly IContext _dbContext;

    public UnitOfWork(IContext dbContext) : base(dbContext)
    {
        _dbContext = dbContext;
    }

    public ISomeRepository SomeRepository => _someRepository ?? (_someRepository = new SomeRepository(_dbContext));
}

public class BookingBusiness : IBookingBusiness
{
    protected IAllotmentUnitOfWork UnitOfWork { get; }

    public AllotmentBusinessBase(IUnitOfWork unitOfWork)
    {
        UnitOfWork = unitOfWork;
    }

    ...
    business methods here
    ...
}

So my idea is when reaching business, I query the configuration database for the connection string for the current user (the current unit of work injected points to that database), and somehow use that connection to instantiate a new unit of work for to connect to the correct database. Any ideas how i can achieve this using my current setup?

1
1
2/26/2018 3:04:49 PM

Accepted Answer

You should prevent injecting objects into the object graph that change based on runtime information. The question here is whether or not the connection string is still a constant value (won't change after the application started), or can change from request to request (for instance, when each user gets its own connection string).

In case the connection string is a constant, the solution is simple: Just request the connection string at start-up and use it indefinitely, just as you already are doing currently.

If your connection string isn't a constant value from the config file, but runtime information, it and its consuming DbContext should not be injected anymore directly into the object graph. Instead, you should define an abstraction that allows requesting the correct DbContext based on runtime information, such as logged in user.

So instead of injecting an IContext into SomeRepository and UnitOfWork, inject an IContextProvider, which can be defined as follows:

public interface IContextProvider
{
    IContext Context { get; }
}

Your DataRepositoryBase can use IContextProvider as follows:

public IEnumerable<TEntity> Get()
{
    return this.contextProvider.Context.Get<TEntity>();
}

public TEntity Get(object id)
{
    return this.contextProvider.Context.Find<TEntity>(id);
}

The part left is to define an implementation for IContextProvider that can load the right connection string from the database, and create and cache a DbContext based on that connection string. Considering the limited amount of information given, this is only something you will know how to do.

0
2/26/2018 3:19:06 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow