Можно ли изменить порядок маршрутов в таблице маршрутизации при использовании маршрутизации атрибутов?
Итак, я переключаю область с помощью AreaRegistration на использование Routing Attribute. Я столкнулся с проблемой, которая, по-видимому, вызвана порядком загрузки маршрутов в таблицу маршрутизации. Я решил проблему в AreaRegistration, загрузив ее в проблемный маршрут последним, так что только если все остальные маршруты не совпадают, этот маршрут будет согласован. При использовании маршрутизации атрибутов это не представляется возможным. У меня есть параметр Order при создании маршрута, но это не влияет на то, как вещи попадают в таблицу маршрутизации, но очень узко.
Здесь маршрут, который у меня есть в файле AreaRegistration:
context.MapRoute(
name: "ActionItems_home",
url: "ActionItems/{group}/{statuses}/{overdueOnly}",
defaults: new { controller = "Home", action = "Index", group = "All", statuses = "New,Open", overdueOnly = false },
namespaces: new string[] { "IssueTracker.Areas.ActionItems.Controllers" }
);
Теперь, когда я пытаюсь переключить это на Маршрутизацию атрибутов, единственное, что подходит для работы, это:
[Route("", Order = 4)]
[Route("{group:regex(^(?!Item|DecisionLogs))?}", Order = 3)]
[Route("{group:regex(^(?!Item|DecisionLogs))}/{statuses=New,Open?}", Order = 2)]
[Route("{group:regex(^(?!Item|DecisionLogs))}/{statuses=New,Open}/{overdueOnly:bool=false?}", Order = 1)]
Обратите внимание, что мне нужно добавить регулярное выражение, потому что иначе контроллер элемента не будет вызван - вместо этого я получаю строку "Item", которая передается как параметр group
. Но регулярное выражение не особенно помогает в том, как отображаться URL-адрес.
Я хотел бы, чтобы необязательные параметры были подавлены в URL-адресе, если они не являются стандартными. Я попытался указать параметры как необязательные, со значениями по умолчанию, и как необязательные, так и со значениями по умолчанию. Ни один из них, похоже, действительно не делает трюк.
Текущее решение по крайней мере представляет URL-адрес без запроса, но они включают в себя необязательные параметры и делают вещи уродливыми. На данный момент я просто оставил вопиющие маршруты, которые будут определены в файлах AreaRegistration
, и не украсил их фрагментами [Route()]
.
Ответы
Ответ 1
Ваша настоящая проблема заключается в том, как настроить исходный маршрут с помощью маршрутизации атрибутов. Проблема порядка - это просто побочный эффект настройки нескольких маршрутов вместо одного.
Чтобы достичь желаемой конфигурации, вы можете создать собственный атрибут RouteAttribute и сделать все, что вам нужно внутри.
public class OptionalsRouteAttribute : RouteFactoryAttribute
{
private object _defaults;
public OptionalsRouteAttribute(string template, object defaults)
: base(template)
{
Defaults = defaults;
}
[...]
}
Здесь вы можете увидеть образец
И оригинальный источник RouteFactoryAttribute для справки
Я боюсь, что у меня нет времени прямо сейчас, чтобы обеспечить реальную реализацию, но я надеюсь, что это приведет вас в правильном направлении.
UPDATE
Я дал эту попытку, и следующее очень простое решение работает так, как ожидалось. Моя реализация атрибута специфична для образца, который вы предоставили с параметрами группы, статусов и просроченной только, но вы должны иметь возможность создавать более общее решение, которое охватывает все ваши случаи (вам также необходимо добавить пространство имен).
public class OptionalsRouteAttribute : RouteFactoryAttribute
{
public OptionalsRouteAttribute(string template, string group, string statuses, bool overdueOnly)
: base(template)
{
var defaults = new RouteValueDictionary
{
{"group", @group},
{"statuses", statuses},
{"overdueOnly", overdueOnly}
};
Defaults = defaults;
}
public override RouteValueDictionary Defaults { get; }
}
Затем в контроллере:
[OptionalsRoute("ActionItemsAttribute/{group}/{statuses}/{overdueOnly}", "All", "New,Open", false)]
public ActionResult AttributeRouting(string group, string statuses, bool overdueOnly)
{
ViewBag.Message = $"Attribute Routing: Group [{@group}] - Statuses [{statuses}] - overdueOnly [{overdueOnly}]";
return View("Index");
}
И он работает точно так же, как и исходная конфигурация маршрутизации, но использует атрибут.
Ответ 2
ASP.NET MVC является открытым исходным кодом, и он разработан таким образом, что каждый уровень может быть заменен вашим собственным. Вы можете загрузить исходный код, найти проблемную часть и узнать, как она работает. Наконец, замените его собственным кодом.
git clone https://git01.codeplex.com/aspnetwebstack.git
Если вы загрузите этот исходный код, вы найдете класс System.Web.Mvc.RouteAttribute с методом CreateRoute. Я не уверен, но это может быть как-то связано с вашей проблемой.
RouteEntry IDirectRouteFactory.CreateRoute(DirectRouteFactoryContext context)
{
Contract.Assert(context != null);
IDirectRouteBuilder builder = context.CreateBuilder(Template);
Contract.Assert(builder != null);
builder.Name = Name;
builder.Order = Order;
return builder.Build();
}
Поиск ссылок на этом интерфейсе можно найти в классе DefaultDirectRouteProvider.
Другой подход заключается в том, что вы можете попытаться найти работу "Заказ" в проекте. Если вы пропустите тест, не так много вхождений, а некоторые из них находятся в классах классов.
Вы можете снять флажок "Только мой код" в Visual Studio и отладить код ASP.NET MVC.