使用Ninject,您可以按请求解析租户来逐个请求地使用依赖注入。我是通过使用Nuget将添加到我的项目中,然后添加一个类来实现的。该类包含一个例程,您可以在其中注册依赖项。我指定在模块中加载依赖项,而不是直接在此例程中加载。
private static void RegisterServices(IKernel kernel)
{
kernel.Load(new TenantConfigurationModule());
}
该模块随后被指定为:
public class TenantConfigurationModule : NinjectModule
{
public override void Load()
{
IEnumerable<ITenantConfiguration> configuration =
TenantConfigurationProvider provider = new TenantConfigurationProvider(configuration);
Bind<ITenantConfiguration>().ToProvider(provider).InRequestScope();
}
}
基础配置类可以指定为:
public interface ITenantConfiguration
{
string TenantName { get; }
IEnumerable<string> UrlPaths { get; }
}
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" };
}
}
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)
{
string baseUrl = string.Format("{0}://{1}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority);
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;
}
}
然后,您可以根据需要将配置注入控制器、视图、属性等。
以下是一些有用的链接:
通过继承视图类在视图中使用依赖注入:查看链接
查看说明和多租户示例应用程序:查看链接
zowens的示例很有用,但在ASP.NET MVC中实现多租户并不是一项简单的任务。该示例提供了一些好的想法,但我将其用作实现自己想法的基础。该示例将每个租户配置存储在一个单独的C#项目中,然后在启动时搜索配置(可以使用反射进行)以查找要使用的所有租户。每个租户配置项目都可以存储特定于该租户的设置、视图、重写控制器、CSS、图像、JavaScript,而无需更改主应用程序。该示例还使用StructureMap进行依赖注入。我选择了Ninject,但您可以使用您喜欢的任何东西,只要它能够按请求解析即可。
该示例还使用Spark View引擎,以便视图可以轻松地存储在其他项目中。我想坚持使用Razor视图引擎,但这有点棘手,因为视图必须预编译。为此,我使用了David Ebbo的Razor Generator,这是一个带有预编译视图引擎的优秀视图编译器:
请参见链接。
注意:如果您选择在一个独立的项目中实现视图,正确实现视图引擎可能会非常棘手。我不得不实现自己的视图引擎和虚拟路径工厂才能让它正常工作,但这是值得麻烦的。
此外,如果您将资源实现在一个独立的项目中,那么以下链接可能是一个有用的建议,可以从这些项目中检索信息:
请参阅链接
我希望这也有助于在mvc3应用程序中实现多租户。不幸的是,我自己没有一个样例应用程序可以上传到某个地方,因为我的实现与工作项目的实现结合在一起。