我正在使用ASP.Net C#MVC 5开发一个多租户web应用程序。出于与此问题无关的原因,我希望每个租户都有一个单独的数据库,包括Identity 2.0部分。此外,我不想在我的域(即http://tenant.myapp.com
)之前使用租户名称作为主机名。一个通常很容易实现的明显解决方案是在MVC路由配置中使用租户名称:
namespace MyApp
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{tenant}/{controller}/{action}/{id}",
defaults: new { tenant = "Demo", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
这很好,但这种方法似乎有一个缺点。我希望在运行时构建一个connectionString,使用RouteData.Values中的租户,并将该字符串传递给我的ApplicationDbContext。
我怀疑,在初始化过程中,Identity框架被初始化为单例。从模板MVC代码中,您可以获得以下Startup部分。
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
...
}
}
备注指出,"每个请求"都会创建一个实例,但当应用程序初始化时,这段代码似乎只命中一次,而不是每个请求。我希望做的是这样做,将租户传递到ApplicationDbContext的构造函数中。
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// Get the tenant from the routeData
string tenant = "YourCompany"; // Switch to something different from the default set during route configuration, for testing purposes.
if (HttpContext.Current.Request.RequestContext.RouteData.Values["tenant"] != null) tenant = HttpContext.Current.Request.RequestContext.RouteData.Values["tenant"].ToString();
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(() => ApplicationDbContext.Create(tenant));
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
...
}
}
但是,遗憾的是,HttpContext.Current.RequestContext没有RouteData.Values,因为我们在代码命中且没有请求时进行初始化。此代码总是生成一个以"YourCompany"为租户的connectionString。
我几年前开发了完全相同的场景。。。
启动&RouteConfig在global.asax/Application_Start中正常执行,每次iis站点启动仅执行一次。
尝试在global.asax/Application_BeginRequest中创建并设置DbContext。
还有一些其他提示:也许每个HttpRequest应该只有一个DbContext,将其保存在HttpContext.Current.Items["DbContext"]中,以便在子操作或类似操作中使用。
如果你成功或需要更多提示,请告诉我
Frank