MVC3 - 多租户应用程序

3
我正在构建一个多租户MVC3应用程序。什么是最佳实践,什么时候建立租户上下文?
我最初考虑在应用程序启动时使用依赖注入,但那行不通。在应用程序启动时,我知道可以绑定“应用程序”上下文(或主查找数据库),因为它只会因服务器环境而改变。但是租户上下文可以根据请求逐个更改,并且应该通过加密cookie或http会话进行持久化。我认为TempData,ViewData,ViewBag在这里对我没用。
所以我的问题是,在每个请求中,我需要验证租户上下文是否存在。如果是,则从持久性机制中获取它。否则,建立它。在MVC管道的哪个阶段应该进行此检查?
我应该创建一个默认控制器,一个操作筛选器来提供租户的检查/建立,并用操作筛选器装饰控制器,然后让每个控制器都派生自默认控制器吗?

@Dangerous的回答非常深入。我看到了许多不同的多租户实现方式,对于非程序员来说,要么很难使其工作,要么很难理解。这似乎是一个普遍的需求,(如果我可以这么说)需要直接在ASP.net MVC中实现或开源项目。我知道有多种方法可以做到这一点,但是开源项目可以确定一种方法,并且只是一个简单的框架,允许用户挂接他们的“应用程序”。并不是要说我们应该有另一个开源CMS(像Orchard一样-非常好)。 - REMESQ
基于MVC 2和Spark视图引擎的开源项目: https://github.com/zowens/Multi-tenancy-Sample https://github.com/andycwk-tp/Multi-tenancy-Sample(以上为其分支)基于MVC 3和Razor/Webforms视图引擎的开源项目: http://code.google.com/p/multimvc/ - Rad
1个回答

4
使用Ninject,您可以按请求解析租户来逐个请求地使用依赖注入。我是通过使用Nuget将添加到我的项目中,然后添加一个类来实现的。该类包含一个例程,您可以在其中注册依赖项。我指定在模块中加载依赖项,而不是直接在此例程中加载。
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;
    }
}

然后,您可以根据需要将配置注入控制器、视图、属性等。

以下是一些有用的链接:

通过继承视图类在视图中使用依赖注入:查看链接

查看说明和多租户示例应用程序:查看链接

zowens的示例很有用,但在ASP.NET MVC中实现多租户并不是一项简单的任务。该示例提供了一些好的想法,但我将其用作实现自己想法的基础。该示例将每个租户配置存储在一个单独的C#项目中,然后在启动时搜索配置(可以使用反射进行)以查找要使用的所有租户。每个租户配置项目都可以存储特定于该租户的设置、视图、重写控制器、CSS、图像、JavaScript,而无需更改主应用程序。该示例还使用StructureMap进行依赖注入。我选择了Ninject,但您可以使用您喜欢的任何东西,只要它能够按请求解析即可。
该示例还使用Spark View引擎,以便视图可以轻松地存储在其他项目中。我想坚持使用Razor视图引擎,但这有点棘手,因为视图必须预编译。为此,我使用了David Ebbo的Razor Generator,这是一个带有预编译视图引擎的优秀视图编译器:请参见链接
注意:如果您选择在一个独立的项目中实现视图,正确实现视图引擎可能会非常棘手。我不得不实现自己的视图引擎和虚拟路径工厂才能让它正常工作,但这是值得麻烦的。
此外,如果您将资源实现在一个独立的项目中,那么以下链接可能是一个有用的建议,可以从这些项目中检索信息:请参阅链接 我希望这也有助于在mvc3应用程序中实现多租户。不幸的是,我自己没有一个样例应用程序可以上传到某个地方,因为我的实现与工作项目的实现结合在一起。

嗨@Dangerous,如果您能分享一下如何为我的自定义视图引擎创建自定义虚拟路径工厂的知识,那将非常棒,因为我在这个点上卡住了。 - Manaf Abu.Rous

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接