Setting the connection string of a DBContext in my repository class using Ninject
Asked Answered
C

1

0

I have an MVC 5 application that uses EF 6 and implements Repository pattern with dependency injection using the DI container Ninject. The connection string for the dbcontext is stored in the Web.config file which the EF Context properly finds. Everything works fine. Lately, I have a requirement that the connection to my DBContext need to be determined at runtime and connect to different databases (but with exactly the same structure). So, I need to change the sql connectionstring part from the entity connectionstring at run-time before the repository is instantiated. I would really appreciate some help in doing it. I am not a DI guru; know just enough Ninject to get my things going.

Here is my Repository Base Interface:

public interface IRepositoryBase<T> where T : class
{
    void Add(T entity, string userGuid = "");
    void Delete(T entity);
    // ... removed other method signatures for brevity
}

My Repository base implementation:

public abstract class RepositoryBase<D, T> : IRepositoryBase<T>, IDisposable
where T : class
where D : DbContext, new()
{
    private Guid? currUserGuid = null;
    private D dataContext;
    protected D DataContext
    {
        get
        {
            if (dataContext == null)
                dataContext = new D();
            return dataContext;
        }
        set { dataContext = value; }
    }

    public IQueryable<T> FindBy(Expression<Func<T, bool>> predicate)
    {
        return DataContext.Set<T>().Where(predicate);
    }
    public virtual IQueryable<T> GetAll()
    {
        IQueryable<T> query = DataContext.Set<T>();
        return query;
    }

    public virtual void Delete(T entity)
    {
        OperationStatus stat = TryDelete(entity);
    }
    // .... removed rest for brevity
}

Interface and implementation for concrete class:

    public interface ICustomerRepository : IRepositoryBase<Customer>
{
    Customer GetCustomerAndStatus( Guid custGuid );
}
public class CustomerRepository : RepositoryBase<PCDataEFContext, Customer>, ICustomerRepository
{
    public Customer GetCustomerAndStatus( Guid custGuid )
    {
        return DataContext.Customers.Include( x => x.CustStatusType )
        .SingleOrDefault( x => x.PKGuid == custGuid );
    }
}

My Ninject dependency resolver:

    public class NinjectDependencyResolver : IDependencyResolver
{
    private IKernel kernel;

    public NinjectDependencyResolver()
    {
        kernel = new StandardKernel();
        AddBindings();
    }
    public IKernel Kernel { get { return kernel; } }

    private void AddBindings()
    {
        kernel.Bind<ICustomerRepository>().To<CustomerRepository>();
        // ... other bindings are omitted for brevity
    }
}

and finally, here is my Entity Framework generated DBContext:

public partial class PCDataEFContext : DbContext
{
    public PCDataEFContext()
        : base("name=PCDataEFContext")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<Customer> Customers { get; set; }
}

All the above code works great! But as I said in the beginning, I don't know how to inject the connection string into my Repositorybase class at runtime so that I don't have to modify any of my inherited repositories (I have plenty of them). Someone please help.

Babu.

Cardialgia answered 27/12, 2014 at 17:46 Comment(0)
C
0

Could you do it like this?

public partial class PCDataEFContext : DbContext
{
    public PCDataEFContext()
        : base(Util.GetTheConnectionString())
    { }
}

public class MyDerivedContext : PCDataEFContext
{
    public MyDerivedContext()
        : base()
    { }
}

class Util
{
    public static string GetTheConnectionString()
    {
        // return the correct name based on some logic...
        return "name=PCDataEFContext";
    }
}

Another way of doing it, could be in the RepositorBase class you defined, by altering the connectionstring after the creation of the dbcontext:

    protected D DataContext
    {
        get
        {
            if (dataContext == null)
            {
                dataContext = new D();
                dataContext.Database.Connection.ConnectionString = "the new connectionstring";
            }
            return dataContext;
        }
        set { dataContext = value; }
    }
Chalutz answered 27/12, 2014 at 17:52 Comment(5)
Sorr, my comment got posted before I could finish it. My understanding is that the connection string will still get set at application start or at the point of instantiation. How would I set the connection only when a new repository is required in the application?Cardialgia
If you want to change the connectionstring of an instantiated dbcontext, you can do it with ctxt.Database.Connection.ConnectionString = "new connection string"Chalutz
Thanks again codemonkey. My question is where would I add this line of code? I don't want to do this in every repository I have. I would like to do this in the base repository or some other common place. Also, I want to pass this string as a parameter to the repository so that I can pass different connection string at different times. My concern is if this approach will work at runtime or will be resolved at compile time?Cardialgia
The static function call will be executed and return the connection string you want it to return when you create a new context of the type PCDataEFContext or any other context based upon this type (at runtime that is)Chalutz
Thanks codemonkey. I am marking your answer as accepted. I have not tested your suggestion. But I think this should work. I will let you know the result.Cardialgia

© 2022 - 2024 — McMap. All rights reserved.