如何在asp.net mvc中动态更改连接字符串

时间:2018-04-09 18:03:30

标签: c# asp.net asp.net-mvc entity-framework

在我们公司,我们有一个为1个数据库制作的应用程序。现在我被告知要为每个客户公司使用单独的数据库进行多租户。所以我创建了一个新的数据库,我将存储所有用户并存储他们的公司名称,我将用它来更改数据库。 我想做的事: 1.用户登录 2.后端检查用户的公司名称 3.检索到的公司名称将分配给dbcontext:base,它将使用公司名称切换数据库

当然,我在stackoverflow和其他地方查看了与此相关的其他问题,大多数人都说这是一个解决方案:

    public FacilityEntities() : base("name=Demo") { }
    public FacilityEntities(string dbConnection) : base(dbConnection)
    {
    }

并且大多数人都说这很有效。但这对我不起作用。 虽然没有推荐,但我也尝试在运行时更改web.config文件,但每次用户登录时,应用程序都会刷新,无法完成登录过程。

我现在的代码:

登录

        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);

        switch (result)
        {
            case SignInStatus.Success:
                returnUrl = CheckFirstLogin(model.Email, returnUrl);
                using (var context = new Facility.AdgarWeb.Models.UserCommonDBContext())
                {
                    var companyName = context.CommonUser.Where(x => x.CommonUserEmail == model.Email).FirstOrDefault().CommonUserCompanyName;

                    new FacilityEntities(companyName.ToString());

                }
                        await OnSignInSuccess(model);
                //FormsAuthentication.SetAuthCookie(model.Email, false);
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }

的DbContext

    public partial class FacilityEntities : DbContext
{        

    public FacilityEntities() : base("name=Demo") { }
    public FacilityEntities(string dbConnection) : base(dbConnection)
    {

    }

}

当我设置调试点时 1。

public FacilityEntities() : base("name=Demo") { }

和 2。

public FacilityEntities(string dbConnection) : base(dbConnection)

我可以看到该应用首先点击第一个代码,然后点击第二个代码,但最终会先回复。

我还发现我有DbFactory文件: DbFactory

        FacilityEntities dbContext;
    public FacilityEntities Init()
    {
        return dbContext ?? (dbContext = new FacilityEntities());
    }

    protected override void DisposeCore()
    {
        if (dbContext != null)
            dbContext.Dispose();
    }
}

请有人帮我解决这个问题。

UPDATE 我知道我可以这样使用它:

public FacilityEntities() : base("name=Demo") { }
public FacilityEntities(string dbConnection) : base(dbConnection)
{
}

        using(var db = new FacilityEntities(dbConnection) 
{
//do sth in this db
}

但是如何设置更改的数据库而不必使用using(){}?如何让登录的用户始终使用此数据库?每次我对db执行某些操作时,是否必须调用此新数据库?有没有办法将此更改的数据库设置为此登录用户的“主数据库”?

4 个答案:

答案 0 :(得分:2)

对于这个问题,我只需将新实体的第二个连接字符串添加到web.config

<connectionStrings>
 <add name="DefaultConnection" .../>
 <add name="DefaultConnection2" .../>
</connectionStrings

答案 1 :(得分:1)

您不一定需要从web.config获取连接字符串。您可以使用此代码直接传递连接字符串

public FacilityEntities(string connString)
{
    this.Database.Connection.ConnectionString = connString;
}

或者如果您的所有租户的连接字符串相同且只有数据库名称不同,则可以在web.config中添加连接字符串,并将数据库名称替换为CompanyName

<强>的Web.Config

<connectionStrings>
  <add name="FacilityEntities" connectionString="Server=.;Database=_DBNAME_;User Id=myUsername; Password=myPassword;" providerName="System.Data.SqlServerCe.4.0"/>    
</connectionStrings>

<强>的DbContext

public FacilityEntities(string companyName)
{
    string connString = ConfigurationManager.ConnectionStrings["FacilityEntities"].ConnectionString;
    connString = connString.Replace("_DBNAME_", companyName);
    this.Database.Connection.ConnectionString = connString;
} 

这样您就可以动态选择数据库名称。

答案 2 :(得分:0)

您的dbcontext类有2个构造函数。 1个默认值和一个参数化。您需要调用参数化版本

return dbContext ?? (dbContext = new FacilityEntities());

尝试将其更改为

return dbContext ?? (dbContext = new FacilityEntities("New Connection String"));

在任何一种情况下,您都必须修改连接代码。

答案 3 :(得分:0)

根据objectively C创建多个连接字符串的建议,我发现它的工作方式如下:

public FacilityEntities() : base("name=Demo") { } // parameterless
public FacilityEntities(string dbConnection) : base($"name={dbConnection}") { } // with param

唯一缺少的东西基本构造函数中的 name=...

现在您可以通过以下方式(简化代码)使用它:

var dbConnection = "DefaultConnection2";
using (var ctx = new FacilityEntities(dbConnection))
{
   // any EF queries using ctx go here
}

注意:由于FacilityEntities可能是由生成的c#代码组成的EDMX的一部分,因此,最好将参数构造函数添加为单独的C#文件(例如FacilityEntities.cs)。相同的名称空间,其中包含一个partial

namespace YourNameSpace // important: use the same namespace your EDMX is using
{
    public partial class FacilityEntities 
    {
        public FacilityEntities(string dbConnection) : base($"name={dbConnection}") { } 
    }
}

无参数构造函数已经存在(在生成的代码中),因此您只能使用参数指定一个。