MVC 2 AreaRegistration路由顺序

时间:2009-10-28 20:41:26

标签: asp.net-mvc .net-3.5 routes asp.net-mvc-routing

我注意到在MVC 2 Preview 2中,AreaRegistration正在以任意顺序加载每个区域的路由。有没有一种好方法让一个先于另一个?

例如,我有两个区域 - “网站”和“管理员”。两者都有一个“博客”控制器。

我想要以下内容:

/admin/ --> go to Admin's Blog controller
/       --> go to Site's Blog controller. 

问题在于它首先加载网站的路线,因此当我转到网址“/ admin /”时,它匹配{controller}/{action}/{id}而不是admin/{controller}/{action}/{id}。然后我得到404,因为“站点”区域中没有管理员控制器。

两个区域都默认为“博客”控制器。我意识到我可以简单地将site/{controller}/...作为网址,但如果可能的话,我宁愿把它放在根端。我还尝试在全局RegisterRoutes函数中保留默认路由,但是,它不会被发送到“站点”区域。

提前致谢!

4 个答案:

答案 0 :(得分:30)

除了Haacked所说的,很有可能订购区域注册(以及他们的路线)。您所要做的就是手动注册每个区域,无论您想要什么顺序。它不像调用RegisterAllAreas()那样流畅,但它绝对可行。

protected void Application_Start() {
    var area1reg = new Area1AreaRegistration();
    var area1context = new AreaRegistrationContext(area1reg.AreaName, RouteTable.Routes);
    area1reg.RegisterArea(area1context);

    var area2reg = new Area2AreaRegistration();
    var area2context = new AreaRegistrationContext(area2reg.AreaName, RouteTable.Routes);
    area2reg.RegisterArea(area2context);

    var area3reg = new Area3AreaRegistration();
    var area3context = new AreaRegistrationContext(area3reg.AreaName, RouteTable.Routes);
    area3reg.RegisterArea(area3context);
}

另一种选择是获取RegisterAllAreas()的代码,将其复制到您自己的应用程序中,并构建您自己的机制来确定订单。如果您想要内置方法所具有的所有花哨的缓存逻辑,那么复制相当多的代码,但您的应用可能甚至不需要。

答案 1 :(得分:7)

目前无法订购区域。但是,我认为尝试使每个区域尽可能独立于其他区域是有意义的,因此顺序无关紧要。

例如,不是使用默认的{controller} / {action} / {id}路由,而是将其替换为每个控制器的特定路由。或者为该默认路线添加约束。

我们正在考虑允许订购的选项,但我们不想让功能过于复杂。

答案 2 :(得分:4)

我做出了这个解决方案:

AreaUtils.cs

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

    namespace SledgeHammer.Mvc.Site
    {
        public static class Utils
        {
                public static void RegisterArea<T>(RouteCollection routes,
    object state) where T : AreaRegistration

            {
                 AreaRegistration registration =
     (AreaRegistration)Activator.CreateInstance(typeof(T));

                    AreaRegistrationContext context =
     new AreaRegistrationContext(registration.AreaName, routes, state);

                    string tNamespace = registration.GetType().Namespace;
                    if (tNamespace != null)
                {
                    context.Namespaces.Add(tNamespace + ".*");
                }

                registration.RegisterArea(context);
            }
        }

    }

在global.asax中:

Utils.RegisterArea<SystemAreaRegistration>(RouteTable.Routes, null);
Utils.RegisterArea<ClientSitesAreaRegistration>(RouteTable.Routes, null);

//AreaRegistration.RegisterAllAreas(); do not dublicate register areas

对生成区域注册码没有重新更改。 我还在路由中使用自定义constrant来按请求(系统域或用户站点)中的域类型过滤路由。

这是我的区域注册例如:

namespace SledgeHammer.MVC.Site.Areas.System
{
    public class SystemAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return "System"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "System_Feedback",
                "Feedback",
                new { controller = "Feedback", action = "Index" }
            );
            context.MapRoute(
                "System_Information",
                "Information/{action}/{id}",
                new { controller = "Information", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}



namespace SledgeHammer.MVC.Site.Areas.ClientSites
{
    public class ClientSitesAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return "ClientSites"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "ClientSites_default",
                "{controller}/{action}/{id}",
                new { controller = "Site", action = "Index", id = UrlParameter.Optional },
                new { Host = new SiteInGroups("clients") }
            );
        }
    }
}

答案 3 :(得分:4)

供参考,

在MVC3(不了解MVC2)中,当您只想将根映射到特定区域/控制器时,您可以简单地使用全局路由。 只需记住指定名称空间/区域。

    routes.MapRoute(
      "CatchRoot", "",
      new { controller = "SITEBLOG-CONTROLLER-NAME", action = "Index"} 
     ).DataTokens.Add("area", "SITE-AREA-NAME");