MVC 2 AreaRegistration Маршруты Заказать

Я заметил, что в MVC 2 Preview 2, AreaRegistration загружает маршруты для каждой области в произвольном порядке. Есть ли хороший способ получить один за другим?

Например, у меня есть две области - "Сайт" и "Админ". Оба имеют контроллер "Blog".

Я бы хотел:

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

Проблема заключается в том, что сначала загружается маршрут сайта, поэтому он подходит для {controller}/{action}/{id} вместо admin/{controller}/{action}/{id}, когда я перехожу на url "/admin/". Затем я получаю 404, потому что в области "Сайт" нет контроллера администратора.

Обе области по умолчанию используют контроллер "Блог". Я понимаю, что я мог бы просто положить site/{controller}/... в качестве URL-адреса, но я предпочел бы иметь его в корне, если это возможно. Я также попытался сохранить маршрут по умолчанию в глобальной функции RegisterRoutes, однако он не отправляется в область "Сайты".

Спасибо заранее!

Ответ 1

В настоящее время невозможно заказать зоны. Тем не менее, я считаю, что имеет смысл попытаться сделать каждую область независимой от других областей, чтобы порядок не имел значения.

Например, вместо того, чтобы иметь маршрут по умолчанию {controller}/{action}/{id}, возможно, замените его на определенные маршруты для каждого контроллера. Или добавьте ограничение на этот маршрут по умолчанию.

Мы рассматриваем опции, позволяющие упорядочивать, но мы не хотим чрезмерно усложнять эту функцию.

Ответ 2

Помимо того, что сказал Хаакед, очень можно заказать регистрацию мест (и, следовательно, их маршруты). Все, что вам нужно сделать, это зарегистрировать каждую область вручную, в любом порядке. Это не так гладко, как вызов 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(), скопировать его в собственное приложение и создать собственный механизм для определения заказа. Скорее всего, это код для копирования, если вы хотите, чтобы всякая логика кэширования использовала встроенный метод, но ваше приложение может даже не понадобиться.

Ответ 3

Я делаю это решение:

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") }
            );
        }
    }
}

Ответ 4

Для справки,

В MVC3 (не знаю о MVC2), когда вы просто хотите сопоставить корень с определенной областью/контроллером, вы можете просто использовать глобальный маршрут. Просто не забудьте указать пространство имен/область.

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