asp.net mvc 6用于asp.net身份的动态数据库连接

时间:2016-03-16 09:51:28

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

我有

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()从

添加连接字符串

配置[“数据:DefaultConnection:MigrationConnectionString”]

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

如何为 companyResult.ConnectionString 中的 sermanager(asp.net identity)设置连接字符串?

任何帮助将不胜感激。

感谢。

1 个答案:

答案 0 :(得分:2)

问题在于你尝试这样做的方式,很可能它不会起作用。在进入登录方法之前,您必须提前知道公司号码,例如。将其作为查询参数传递或使用子域来决定或采用其他方法。 最近我必须在ASP.NET Core 1.0中做类似的事情。无法向您发送确切的代码,因为我最终在所有这些内容中添加了基础结构代码,但我会尝试给您一些指导。

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

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将使用正确的连接字符串。 但是你开始的方式,我非常怀疑你会让它发挥作用。因为在您尝试替换连接字符串的位置,所有内容都已经过实例化和配置。 我再次手动输入代码片段来说明这个想法。 此外,请考虑使用中间件中的IMemoryCache来缓存连接字符串,并避免对每个请求执行db调用。