如何在除一个控制器之外的所有控制器中使用多租户路由?

时间:2013-10-25 20:36:01

标签: asp.net-mvc

我们的应用有多个租户。每个租户都有一个分配给他们的短代码,供用户了解。我想在我的URL中使用该代码作为路由参数,并让Ninject将租户的数据库连接字符串注入DbContext到特定于租户的控制器中。

因此,检查我有一个CarController,每个租户都有自己的产品。这些网址看起来像{tenantcode} / {controller} / {action}。我理解如何做这个部分。

但是,我有几个控制器不应该由租户实例化。具体而言,家庭控制器和帐户控制器用于登录/注册。这些都没关系。

我需要的示例网址:

  • myapp.com/ - HomeController
  • myapp.com/Account/Login - AccountController
  • myapp.com/GM/Car/Add - 已注入GM的DbContext的CarController
  • myapp.com/Ford/Car/Add - 注入福特DbContext的CarController

如何从路线中排除某些控制器?运行ASP.NET MVC 5.


非常感谢Darko Z让我朝着正确的方向前进。我最终使用传统路由的混合,以及MVC 5中新的基于属性的路由。

首先,“排除”路线用新的RouteAttribute类

进行修饰
public class HomeController : Controller
{
    private readonly TenantContext context;

    public HomeController(TenantContext Context)
    {
        this.context = Context;
    }

    //
    // GET: http://myapp.com/
    // By decorating just this action with an empty RouteAttribute, we make it the "start page"
    [Route]
    public ActionResult Index(bool Error = false)
    {
        // Look up and make a nice list of the tenants this user can access
        var tenantQuery =
            from u in context.Users
            where u.UserId == userId
            from t in u.Tenants
            select new
            {
                t.Id,
                t.Name,
            };

        return View(tenantQuery);
    }
}

// By decorating this whole controller with RouteAttribute, all /Account URLs wind up here
[Route("Account/{action}")]
public class AccountController : Controller
{
    //
    // GET: /Account/LogOn
    public ActionResult LogOn()
    {
        return View();
    }

    //
    // POST: /Account/LogOn
    [HttpPost]
    public ActionResult LogOn(LogOnViewModel model, string ReturnUrl)
    {
        // Log on logic here
    }
}

接下来,我注册了Darko Z建议的租户通用路线。在制作其他路线之前调用MapMvcAttributeRoutes()非常重要。这是因为我的基于属性的路线是“例外”,就像他说的那样,这些例外必须在顶部,以确保它们首先被拾取。

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

        // exceptions are the attribute-based routes
        routes.MapMvcAttributeRoutes();

        // tenant code is the default route
        routes.MapRoute(
            name: "Tenant",
            url: "{tenantcode}/{controller}/{action}/{id}",
            defaults: new { controller = "TenantHome", action = "Index", id = UrlParameter.Optional }
        );
    }
}

1 个答案:

答案 0 :(得分:2)

因此,我确定您知道您按照从最具体到最通用的顺序在MVC中指定路由。所以在你的情况下,我会做这样的事情:

//exclusions - basically hardcoded, pacing this at the top will 
//ensure that these will be picked up first. Of course this means 
//you must make sure that tenant codes cannot be the same as any 
//controller name here
routes.MapRoute(
    "Home",                                              
    "Home/{action}/{id}",                         
    new { controller = "Home", action = "Index", id = "" } 
);

routes.MapRoute(
    "Account",                                              
    "Account/{action}/{id}",                         
    new { controller = "Account", action = "Index", id = "" } 
);

//tenant generic route
routes.MapRoute(
    "Default",                                              
    "{tenantcode}/{controller}/{action}",                         
    new { tenantcode = "Default", controller = "Tenant", action = "Index" } 
);

//default route
routes.MapRoute(
    "Default",                                              
    "{controller}/{action}/{id}",                         
    new { controller = "Home", action = "Index", id = "" } 
);

如果排除的控制器少于需要租户代码的控制器,这显然是唯一的好处。如果没有,那么你可以采取相反的方法并扭转上述情况。这里的主要内容是(很高兴被证明是错误的)在AddRoute调用中无法进行通用忽略。虽然有一个IgnoreRoute,但它完全不应用任何路由规则,并用于静态资源。希望有所帮助。