Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
765 views
in Technique[技术] by (71.8m points)

asp.net mvc - How to change database name in dbcontext connection string at runtime

My Asp.Net MVC application is setup as follows. There are 4 projects in solution.

  • ge.Web
  • ge.BLL
  • ge.Core
  • ge.Entities

Controller in ge.Web initializes a repository object present in ge.Core

 public class MapsController : Controller
 {
      private AssessmentRepository repAssessments = new AssessmentRepository("name=GEContext", schoolCode);

      public ActionResult DisplaySearchResults()
      {
        .....
      }
  }

Assessments Repository

  public class AssessmentRepository : Repository<Assessment>, IAssessmentRepository
{
    public AssessmentRepository(string connString, string schoolCode)
        :base(connString, schoolCode)
    { }
 }

Repository

  public class Repository<TEntity> : IRepository<TEntity> where TEntity:class
{
    protected readonly GEContext context;


    public Repository(string connString, string schoolCode) {
        context = new GEContext(connString);
    }
 }

GEContext

 public class GEContext : DbContext
 {
    public GEContext(string connString):base(connString) 
    {
        this.Configuration.LazyLoadingEnabled = false;
        Database.SetInitializer(new MySqlInitializer());
    }
  }

DbContext

public class DbContext : IDisposable, IObjectContextAdapter
{
    public DbContext(string nameOrConnectionString);
}

Web.Config

 <add name="GEContext" connectionString="server=localhost;port=4040;uid=root;pwd=xxx;database=ge" providerName="MySql.Data.MySqlClient" />

now i want to replace "database=ge" present in web.config with database=ge_[schoolCode]. at runtime How can i go about it?

UPDATE My solution did not work. so i am stating the problem once again.

Web.Config

I have changed My config file to the following (previously GEContext was the only connection string)

<connectionStrings>
<add name="GEContext_sc001" connectionString="server=localhost;port=4040;uid=root;pwd=blabla;database=db_sc001" providerName="MySql.Data.MySqlClient" />
<add name="GEContext_sc002" connectionString="server=localhost;port=4040;uid=root;pwd=blabla;database=db" providerName="MySql.Data.MySqlClient" />

<appSettings>
     <add key="SchoolCodes" value="sc001,sc002"/>

these are the allowed schoolCodes

Now when the user enters schoolcode at login screen, it is validated against the codes present in SchoolCodes key. and if yes, then it should try to connect to the connectionString for that particular connection. Now when my code comes to

UserManager.FindAsync

in Login function of AccountController, it crashes trying to find GEContext. Where is that set? and how can i change it?

I have changed the repository calling in controller as follows

private static string schoolCode = (string)System.Web.HttpContext.Current.Session["SchoolCode"];

    private AssessmentRepository repAssessments = new AssessmentRepository("name=GEContext_" + schoolCode);

UPDATE-2 Following is present in ge.Web

IdentityConfig.cs

  public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
    public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
        : base(store)
    {
    }

     public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
    {
        var manager = new ApplicationUserManager(new UserStore<ApplicationUser, Role, int, UserLogin, UserRole, UserClaim>(context.Get<ApplicationDbContext>()));
  ...........
 }

The following is present in ge.Core

ApplicationDbContext

 public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Role, int, UserLogin, UserRole, UserClaim>
{

     public ApplicationDbContext(string connString)
        : base(connString)
    {
        Database.SetInitializer(new MySqlInitializer());
    }

    public static ApplicationDbContext Create()
    {

        return new ApplicationDbContext("name=GEContext_");
    }
}

How can i pass schoolCode from ge.web to ge.Core (answer should be straight forward but currently i cant get my head around it)

UPDATE-3

As told by itikhomi and taking help from this post I have changed my code as follows

  1. in ApplicationDbContext class added the following

    public static ApplicationDbContext Create(string scCode){ return new ApplicationDbContext("name=GEContext_" + scCode); }

  2. in AccountController Login

    var appDbContext = ApplicationDbContext.Create(model.SchoolCode);

                Request.GetOwinContext().Set<ApplicationDbContext>(appDbContext);
    

it still does not hit the correct database

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have two ways

1)

    using System.Data.SqlClient;

         public class Repository<TEntity> : IRepository<TEntity> where TEntity:class
        {
            protected readonly GEContext context;


            public Repository(string connString, string schoolCode) {
                context = new GEContext(connString);
                var connection = new SqlConnectionStringBuilder(context.Database.Connection.ConnectionString);
                connection.InitialCatalog = "YOUR_PREFIX_FROMSOMEWHERE"+schoolCode;
                context.Database.Connection.ConnectionString = connection.ConnectionString;
            }
         }

2) if you wants to switch connection when it opened before use ChangeDatabase:

//open connection if it close
    context.Database.Connection.ChangeDatabase("DATABASE-NAME");

NOTE: if use ChangeDatabase connection should be already opened

FOR UPDATE3:

You need to do somethink like this:

 public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {

        }

        public ApplicationDbContext(string schoolCode)
            : base(schoolCode)
        {
            var connection = new SqlConnectionStringBuilder(this.Database.Connection.ConnectionString);
            connection.InitialCatalog = "YOUR_PREFIX_FROMSOMEWHERE" + schoolCode;
            this.Database.Connection.ConnectionString = connection.ConnectionString;
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }

in account controller:

public ApplicationSignInManager SignInManager
        {
            get
            {

                if (_signInManager == null)
                {
                    var code = HttpContext.Request.Form.Get("SchoolCode");//Get from FORMQueryStringSession whatever you wants
                    if (code != null)
                    {
                        HttpContext.GetOwinContext().Set<ApplicationSignInManager>(new ApplicationSignInManager(_userManager, HttpContext.GetOwinContext().Authentication));
                    }
                    _signInManager = HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
                }

                return _signInManager;
            }
            private set
            {
                _signInManager = value;
            }
        }

 public ApplicationUserManager UserManager
        {
            get
            {
                if (_userManager == null)
                {
                    var code = HttpContext.Request.Form.Get("SchoolCode");//Get from FORMQueryStringSession whatever you wants
                    if (code != null)
                    {
                        var appDbContext = new ApplicationDbContext(code);

                        HttpContext.GetOwinContext().Set<ApplicationDbContext>(appDbContext);
                        HttpContext.GetOwinContext().Set<ApplicationUserManager>(new ApplicationUserManager(new UserStore<ApplicationUser>(appDbContext))); //OR USE your specified create Method
                    }
                    _userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
                }
                return _userManager;
            }
            private set
            {
                _userManager = value;
            }
        }

Your problem is in Store of UserManager is created before you change your OWIN context, in this case better to use DI like here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...