Introduction
I am working on a Multi Tenant application that I am programming in ASP.NET MVC with EF6 and Sql Server.
My database structure:
1 base database that holds the tenant properties ( eg Name / Subdomain / Catalogue ).
(Catalogue is the name of his assigned database )
1 database for each customer
For knowing the tenant I use a subdomain lookup:
Entity Framework
Of the base and the default app database I have added a ADO.NET Entity data model
( edmx ) file.
Controllers
To get the correct tenant I have created a new custom controller that overrides the OnActionExecuting
method. If the tenant exists I add the Id of the tenant to the route variables.
// Override OnActionExecuting method which is called every time before the action is called
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var fullAddress = filterContext.HttpContext.Request.Headers["Host"].Split('.');
if (fullAddress.Length < 3)
{
// some code....
}
else
{
var tenantSubdomain = fullAddress[0];
Account currentTenant = db.Accounts.FirstOrDefault(t => t.Subdomain.Equals(tenantSubdomain, StringComparison.CurrentCultureIgnoreCase));
if (currentTenant != null)
filterContext.RouteData.Values["tenant"] = currentTenant.Id;
else
filterContext.Result = new HttpStatusCodeResult(404);
}
base.OnActionExecuting(filterContext);
}
Till here everything is working fine. Now I get stuck for creating and storing the connection with the tenants assigned database.
To connect to the database I need to use the following code:
public SkycountAppEntities dbApp = new SkycountAppEntities(GetConnString(tenant.Catalogue));
//GetConnString renders the connectionstring which includes the tenants catalogue.
But where do I place this line so I do not have to call this in every action? Or can I cache it somewhere along with the authentication cookie?
Can someone guide me in the correct direction?
UPDATE
In this way its working but now I have to create the connection in every action of every controller.
// POST: Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login([Bind(Include = "Username,Password")] User user, string returnUrl)
{
using (SkycountAppEntities dbApp = new SkycountAppEntities(DbEntityFramework.RenderConnectionString(_SkycountAccount.Catalog)))
{
User _user = dbApp.Users.FirstOrDefault(u => u.Username.Equals(user.Username));
if(_user != null && _user.Active && Crypto.VerifyHashedPassword(_user.Password, user.Password))
{
FormsAuthentication.SetAuthCookie(user.Username, false);
if (String.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
return RedirectToAction("Index", "Home");
else
return Redirect(returnUrl);
} else
{
TempData["failed"] = true;
return RedirectToAction("Login", new { returnUrl = returnUrl });
}
}
}