用于动态加载模块的特定于租户的路由

时间:2011-08-30 16:45:04

标签: asp.net asp.net-mvc asp.net-mvc-routing multi-tenant

我正在使用ASP.NET MVC来开发应用程序框架。从本质上讲,最终目标是能够登录管理界面,创建具有自定义设置的新租户,启用他们想要的模块(博客,购物篮等)...完成工作 - 用新网站满足客户。我没有使用单独的应用程序,因为会有很多共享代码,并且以这种方式维护会更容易,而且因为在高峰时段将新的,相同的节点联机起来非常容易。

根据为租户加载的模块,不同的路由适用于每个租户。在我看来,有三种选择:

  • 让所有租户共享相同的路由集 - 但是如果有很多模块,它将搜索它不需要的许多路由,并且某些模块可能会有相互冲突的路由。 / p>

  • 为每个租户添加必要的路由到全局路由集合,并扩展路由类以查看域 - 但随着更多租户的添加,这可能会很快结束数百条路由。

  • 首先找出被访问的租户,然后只搜索他们自己的私人路线集 - 这是理想的,但我已经搜索了几个小时,完全不知道该怎么做!

那么,任何人都可以指出我正确的第三个方案的方向,或解释为什么前两个中的任何一个都不是那么糟糕?

1 个答案:

答案 0 :(得分:0)

如何在您的应用中区分每个网站?如果我们假设每个租户都将通过唯一的域名或子域名进行标识,那么您可以使用一个路由和一些RouteConstraints来完成路由。创建两个约束,一个用于控制器,另一个用于操作。假设您的数据库中有表列出了特定租户的可用控制器/操作,您的约束将如下所示:

using System; 
using System.Web; 
using System.Web.Routing;  

namespace ExampleApp.Extensions 
{ 
    public class IsControllerValidForTenant : IRouteConstraint
    {
        public IsControllerValidForTenant() { }

        private DbEntities _db = new DbEntities();

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            // determine domain
            var domainName = httpContext.Request.Url.DnsSafeHost;
            var siteId = _db.Sites.FirstorDefault(s => s.DomainName == domainName).SiteId;
            // passed constraint if this controller is valid for this tenant
            return (_db.SiteControllers.Where(sc => sc.Controller == values[parameterName].ToString() && sc.SiteId == siteId).Count() > 0);
        }
    }

    public class IsActionValidForTenant : IRouteConstraint
    {
        public IsActionValidForTenant() { }

        private DbEntities _db = new DbEntities();

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            // determine domain
            var domainName = httpContext.Request.Url.DnsSafeHost;
            var siteId = _db.Sites.FirstorDefault(s => s.DomainName == domainName).SiteId;
            // passed constraint if this action is valid for this tenant
            return (_db.SiteActions.Where(sa => sa.Action == values[parameterName].ToString() && sa.SiteId == siteId).Count() > 0);
        }
    }
}

然后,在Global.asax.cs中,按如下方式定义您的路线:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
        new { controller = new IsControllerValidForTenant(), action = new IsActionValidForTenant(),}
    );
}

当请求进入时,约束将检查控制器和操作是否对域有效,以便只有有效的控制器和该租户的操作才能传递RouteConstraints。