I am building a SAAS application and planned for one database per client. I am using Code First EF6 with ASP.Net MVC 4.
There will be 2 context i.e. MasterContext and TenantContext. User will first hit to MasterContext to authenticate user credentials and fetch its Tenant configuration.
Based on fetched Tenant configuration; TenantContext is set to Tenant specific database and used for Tenant CRUD operations.
Please advice how to achieve this.
The idea is to identify the current request tenant_id and use that to fetch the database configuration and create DbContext like the below code.
public AppDbContext : DbContext
{
private const string _defaultCS = "default app connection string";
public AppDbContext() : base(GetConnectionString())
{
}
private string GetConnectionString()
{
return TenantContext.ConnectionString ?? _defaultCS;
}
}
Sample usage
public class StudentRepo
{
public Student Get(Guid id)
{
using(var ctx = new AppDbContext())
{
return ctx.Students.FirstOrDefault(x=>x.Id == id);
}
}
}
This will automatically connect to the logged in tenant database.
You might need to store tenant_id in Auth cookie and read it after PostAuthenticate_Event and store in HttpContext.Current.Items
public static TenantContext
{
public static Guid TenantId
{
get
{
return (Guid)HttpContext.Current.Items["__TenantID"];
}
}
public static string ConnectionString
{
get
{
return TenantConfigService.GetConnectionString(TenantId);
}
}
}
In some HTTP module Init method
context.PostAuthenticateRequest += context_PostAuthenticateRequest;
void context_PostAuthenticateRequest(object sender, EventArgs e)
{
FormsIdentity identity = Thread.CurrentPrincipal.Identity as FormsIdentity;
if (identity != null)
{
HttpContext.Current.Items["__TenantID"] = GetTenantIdFromTicket(identity.Ticket.UserData); // returns tenant_id as guid type
}
}