使用 Ninject,您可以逐个请求地使用依赖注入来解析请求所针对的租户。
我这样做的方法是使用 Nuget 将 NinjectMVC3 添加到我的项目中,然后添加一个 App_Start/NinjectMVC3 类。此类包含一个 RegisterServices(IKernel kernel) 例程,您可以在其中注册您的依赖项。
我指定在一个模块中而不是直接在这个例程中加载我的依赖项:
private static void RegisterServices(IKernel kernel)
{
kernel.Load(new TenantConfigurationModule());
}
然后将模块指定为:
public class TenantConfigurationModule : NinjectModule
{
public override void Load()
{
IEnumerable<ITenantConfiguration> configuration = //Instantiate a list of configuration classes from where they are stored.
//Initialise a ninject provider to determine what configuration object to bind to on each request.
TenantConfigurationProvider provider = new TenantConfigurationProvider(configuration);
//And then bind to the provider specifying that it is on a per request basis.
Bind<ITenantConfiguration>().ToProvider(provider).InRequestScope();
}
}
基本配置类可以指定为:
public interface ITenantConfiguration
{
string TenantName { get; }
IEnumerable<string> UrlPaths { get; }
//whatever else you need for the tenant configuration
}
public abstract class TenantConfiguration : ITenantConfiguration
{
public string TenantName { get; protected set; }
public IEnumerable<string> UrlPaths { get; protected set; }
}
然后指定实际配置:
public class TenantOneConfiguration : TenantConfiguration
{
public MVTTenantConfiguration()
{
TenantName = "MVT";
UrlPaths = new string[] { "http://localhost:50094" }; //or whatever the url may be
}
}
public class TenantOneConfiguration : TenantConfiguration
{
public MVTTenantConfiguration()
{
TenantName = "MVT";
UrlPaths = new string[] { "http://localhost:50095" };
}
}
然后可以编写提供程序:
public class TenantConfigurationProvider : Provider<ITenantConfiguration>
{
private IEnumerable<ITenantConfiguration> configuration;
public TenantConfigurationProvider(IEnumerable<ITenantConfiguration> configuration)
{
if (configuration == null || configuration.Count() == 0)
{
throw new ArgumentNullException("configuration");
}
this.configuration = configuration;
}
protected override ITenantConfiguration CreateInstance(IContext context)
{
//Determine the request base url.
string baseUrl = string.Format("{0}://{1}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority);
//Find the tenant configuration for the given request url.
ITenantConfiguration tenantConfiguration = configuration.Single(c => c.UrlPaths.Any(p => p.Trim().TrimEnd('/').Equals(baseUrl, StringComparison.OrdinalIgnoreCase)));
if (tenantConfiguration == null)
{
throw new TenantNotFoundException(string.Format("A tenant was not found for baseUrl {0}", baseUrl));
}
return tenantConfiguration;
}
}
然后您可以根据需要将配置注入到控制器、视图、属性等中。
以下是一些有用的链接:
通过继承视图类在视图中使用依赖注入:see link
要查看描述和多租户示例应用程序:see link
zowens 的示例有很多内容,但在 asp.net mvc 中实现多租户并不是一项简单的任务。这个例子提供了一些很好的想法,但我用它作为实现我自己的基础。此示例将每个租户配置存储在单独的 c# 项目中,然后在启动时搜索配置(您可以为此使用反射)以查找要使用的所有租户。然后,每个租户配置项目可以存储特定于该租户的设置、视图、覆盖控制器、css、图像、javascript,而无需更改主应用程序。此示例还使用 StructureMap 进行依赖注入。我选择了 Ninject,但你可以使用任何你喜欢的东西,只要它在请求的基础上解决。
此示例还使用 Spark View 引擎,以便可以轻松地将视图存储在其他项目中。我想坚持使用剃刀视图引擎,但这有点棘手,因为必须预编译视图。为此,我使用了 David Ebbos razor 生成器,它是一个出色的视图编译器,提供预编译的视图引擎:see link
注意:如果您确实尝试在单独的项目中实现视图,那么正确实现视图引擎可能会非常棘手。我必须实现自己的视图引擎和虚拟路径工厂才能使其正常工作,但这是值得的。
此外,如果您在单独的项目中实施资源,那么以下链接可能是有关如何从这些项目中检索信息的有用建议:see link
我希望这也有助于在您的 mvc3 应用程序中实现多租户。不幸的是,我自己没有可以上传的示例应用程序,因为我的实现包含在工作项目中的实现中。