Multi Database for Multi Tenant with Code first EF

2019-08-29 07:17发布

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.

1条回答
一纸荒年 Trace。
2楼-- · 2019-08-29 07:44

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
    }
}
查看更多
登录 后发表回答