【问题标题】:asp.net mvc 6 dynamic db connection for asp.net identityasp.net mvc 6 用于 asp.net 身份的动态数据库连接
【发布时间】:2016-07-02 02:54:52
【问题描述】:

我有

Controller 和 IActionResult 如下

 public HomeController(
            UserManager<CustomerApplicationUser> userManager,
            SignInManager<CustomerApplicationUser> signInManager,
            IMemoryCache cache)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _cache = cache;
        }

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{

ViewData["ReturnUrl"] = returnUrl;
var companyResult = new Company();

using (var GeneralCompanyContext = new GeneralCompanyContext())
{
companyResult = await GeneralCompanyContext.Company.FirstOrDefaultAsync(t => t.CompanyNumber == model.CompanyNumber);
}

using (var context = new CustomerContext(companyResult.ConnectionString))
{

var LoginResult = await _signInManager.PasswordSignInAsync(model.Email, model.Password, false, lockoutOnFailure: false);

}     
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{

services.AddEntityFramework().AddSqlServer()
                    .AddDbContext<CustomerContext>()
                    .AddDbContext<GeneralCompanyContext>();

services.AddIdentity<CustomerApplicationUser, IdentityRole>().AddEntityFrameworkStores<CustomerContext>().AddDefaultTokenProviders();
services.AddIdentity<GeneralCompanyApplicationUser, IdentityRole>().AddEntityFrameworkStores<GeneralCompanyContext>().AddDefaultTokenProviders();

}

CustomerContext 类

CustomerContext : : IdentityDbContext<CustomerApplicationUser>
{
 private readonly string _ConnectionString;

     public CustomerContext()
     {
     _ConnectionString = Configuration["Data:DefaultConnection:MigrationConnectionString"]).ToString();
     }

     public CustomerContext(string ConnectionString)
     {
     _ConnectionString = ConnectionString;
     }

   protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_ConnectionString);
        base.OnConfiguring(optionsBuilder);
    }
}

问题:

我有 2 个 dbcontext 作为 CustomerContext 和 GeneralCompanyContext。

CustomerContext 有客户数据库。

GeneralCompanyContext 拥有所有客户的所有数据库连接字符串。

项目何时开始

services.AddEntityFramework().AddSqlServer() 从

添加连接字符串

配置["Data:DefaultConnection:MigrationConnectionString"]

自动。所以当我尝试登录 Index Iactionresult 时,signinmanager 连接字符串总是显示 Configuration["Data:DefaultConnection:MigrationConnectionString"] 连接字符串。

如何从 companyResult.ConnectionString 为 usermanager(asp.net 身份) 设置连接字符串?

任何帮助将不胜感激。

谢谢。

【问题讨论】:

    标签: asp.net-identity asp.net-core-mvc


    【解决方案1】:

    问题是您尝试这样做的方式很可能行不通。您必须提前知道公司编号,甚至在输入登录方法之前,例如将其作为查询参数传递或使用子域来决定或其他方法。 最近我不得不在 ASP.NET Core 1.0 中做类似的事情。由于我最终围绕所有这些添加了基础设施代码,因此无法向您发布确切的代码,但我会尝试为您提供一些指导。

    首先要知道的是,可以替换上下文的OnConfiguring方法中的CustomerContext连接字符串。这是最后的手段。

    Source.

    public class CustomerDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // optionsBuilder.UseSqlServer("Your connection string should injected here.");
        }
    }
    

    下一步是知道何时何地从GeneralCompanyDatabase 获取连接字符串。这应该发生在与 MVC 5 中的 BeginRequest 等效的位置 - 在中间件中。

    public class Tenant
    {
        public string CustomerConnectionString { get; set; }
    }
    
    public class TenantMiddleware
    {
        private readonly RequestDelegate next_;
    
        public TenantMiddleware(RequestDelegate next)
        {
            next_ = next;
        }
    
        public async Task Invoke(HttpContext httpContext, GeneralCompanyContext companyContext)
        {
            // You have to know your company number here somehow !!
            string customerConnectionString = await companyContext.Company.FirstOrDefaultAsync(t => t.CompanyNumber == 1).ConnectionString;
            Tenant tenant = new Tenant{ CustomerConnectionString = customerConnectionString };
    
            httpContext.Items["customerTenant"] = tenant;
    
            await next_(httpContext);
        }
    }
    

    现在您有了连接字符串,您必须在 CustomerDbContext 中使 Tenant 对象可注入

    Startup.cs

    services.AddScoped(prov => 
    prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenant());
    

    GetTenant()是HttpContext的扩展方法。

    public static Tenant GetTenant(this HttpContext context)
    {
        object myObj;
        if (context.Items.TryGetValue("customerTenant", out myObj))
        {
            return myObj as Tenant;
        }
    
        return null;
    }
    

    现在您的 CustomerDbContext 应该如下所示:

    public class CustomerDbContext : DbContext
    {
        private Tenant tenant_;
    
        public CustomerDbContext(Tenant tenant)
        {
            tenant_ = tenant;       
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(tenant.CustomerConnectionString);
        }
    }
    

    此时SignInManager 将使用正确的连接字符串。 但是你开始的方式,我非常怀疑你会不会让它发挥作用。因为您尝试替换连接字符串的所有内容都已实例化和配置。 同样,我只是手动输入了代码 sn-ps 来说明这个想法。 此外,考虑在中间件中使用IMemoryCache 来缓存连接字符串并避免对每个请求进行数据库调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      • 2014-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多