Search code examples
asp.net-mvcentity-frameworkconnection-stringasp.net-identity

C# MVC ASP.NET Identity - Dynamically change ApplicationDbContext connection string during runtime


I have 3 databases, one GlobalDb is used to manage and redirect users the correct database based on login details.

The other 2 databases are different to the GlobalDb but are the the same as each other. Lets call these 2 databases Company1 and Company2.

GlobalDb does not require the identity framework so it is just being connected to by using standard EntityFramework connections, the other 2 do required the Identity framework.

3 connection strings are saved in the web.config.

I can query all databases bases correctly, and they all return data. The main issue i am having is on login, how do i tell the SignInManager which connection string for the database to use?

IdentityModels.cs

public class CompanyDb : IdentityDbContext<ApplicationUser>
{
    public CompanyDb(string CompanyName)
        : base(CompanyName, throwIfV1Schema: false)
    {
    }

    public static CompanyDb Create(string CompanyName)
    {
        return new CompanyDb(CompanyName);
    }

    // Virtual class and table mappings go here.
}

AccountController Login

public async Task<ActionResult> CustomLogin(string Email, string Password, string returnUrl)
    {
        GlobalDb Global = new GlobalDb();

        // check what company the user belongs to based on email.
        var CompanyName = Global.Users.Where(u => u.Email == Email && u.Active == true).Select(u => u.Company).FirstOrDefault();

        // Connect to the desired database to get test data.
        CompanyDb Company = new CompanyDb(CompanyName);
        var DataTest = Company.Users.ToList();


        if (CompanyName != null)
        {
            var result = await SignInManager.PasswordSignInAsync(Email, Password, false, shouldLockout: false); // <-- How to connect to the correct DB?
            switch (result)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid login attempt.");
                    return View("");
            }
        }

        return View("");
    }

I keep getting a null value in the following file and function

IdentityModel.cs

 // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

Solution

  • Ive Figured it out.

    On my login action if just wrapped the SignInManager within a Context Using statement as follows.

    public async Task<ActionResult> CustomLogin(string Email, string Password, string returnUrl)
        {
            GlobalDb Global = new GlobalDb();
    
            // check what company the user belongs to based on email.
            var CompanyName = Global.Users.Where(u => u.Email == Email && u.Active == true).Select(u => u.Company).FirstOrDefault();
    
            if (CompanyName != null)
            {
                using (CompanyDb db = new CompanyDb(CompanyName))
                {
                    var result = await SignInManager.PasswordSignInAsync(Email, Password, false, shouldLockout: false); // <-- How to connect to the correct DB?
                    switch (result)
                    {
                        case SignInStatus.Success:
                            return RedirectToLocal(returnUrl);
                        case SignInStatus.LockedOut:
                            return View("Lockout");
                        case SignInStatus.RequiresVerification:
                            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
                        case SignInStatus.Failure:
                        default:
                            ModelState.AddModelError("", "Invalid login attempt.");
                            return View("");
                    }
                }
    
            }
    
            return View("");
        }