Задание маршрутов при помощи атрибутов
Одним из нововведений в ASP.NET MVC 5 является задание маршрутов при помощи атрибутов, по аналогии с Web API. Такой подход позволяет указывать необходимые настройки непосредственно в самих контроллерах.
Подключаем использование атрибутов
Чтобы активировать маршруты, заданные атрибутами, необходимо вызвать метод MapMvcAttributeRoutes() класса RouteCollection:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(...);
}
}
При этом необходимо учесть что:
- При использовании и атрибутов и правил для определения маршрутов, вызовы MapRoute() должны находиться после MapMvcAttributeRoutes().
- У атрибутов приоритет выше, чем у правил:
- действия с атрибутами получают получают маршруты согласно значениям этих атрибутов не смотря на заданные правила;
- действия без атрибутов получают маршруты согласно правилам.
- При использовании только атрибутов (без правил), не отмеченные ими действия будут не доступны.
Указание на уровне контроллера
Для контроллера можно задать следующие атрибуты:
- [RouteArea("")] – устанавливает область для контроллера.
- [RoutePrefix("")] – определяет значения префикса в маршруте. По сути, это позволяет переопределить имя контроллера.
- [Route(“{action=}”)] – задает значения по умолчанию для всех действий (в данном примере это action).
Указанные значения будут добавляться к определениям маршрутов для всем действий этого контроллера.
Указание на уровне действия
Для отдельного действия применяется атрибут [Route]. Рассмотрим его использование на конкретных примерах.
Определение маршрута
<p>public class BooksController : Controller
{
// Маршрут: /Books/Catalog/
[Route("Books/Catalog/")]
public async Task<ActionResult> Catalog() { ... }
}
[RouteArea("Admin")]
[RoutePrefix("Profiles")]
public class UsersController : Controller
{
// Маршрут: /Admin/Profiles/List/
[Route("List")]
public async Task<ActionResult> List() { ... }
// Маршрут: /Admin/Profiles/{id}/Edit
[Route("{id}/Edit")]
public async Task<ActionResult> Edit(int id) { ... }
}
</p>
В последующих примерах будем считать что у контроллера не заданы [RouteArea] и [RoutePrefix].
Значения по умолчанию
[Route("Books/Read/{id=1}")]
public async Task<ActionResult> Read(int id) { ... }
Опциональные параметры (”?”)
[Route("Books/View/{id?}")]
public async Task<ActionResult> View(int? id) { ... }
Действие View будет соответствовать как маршруту /Books/View так и /Books/View/{id}.
Указание абсолютного маршрута (”~“)
// Маршрут: /dashboard
[Route("~/dashboard")]
public async Task<ActionResult> UserDashboard() { ... }
Ограничение типа значений параметров
Возможны следующие ограничения значений параметров:
| Ограничение | Описание | Пример |
|---|---|---|
| alpha | Буквы латинского алфавита: A-Z и a-z. | {val:alpha} |
| bool | Булевское значение. | {val:bool} |
| datetime | Тип DateTime. | {val:datetime} |
| decimal | Десятичное значение. | {val:decimal} |
| double | Тип double (64-битное число с плавающей точкой). | {val:double} |
| float | Тип float (32-битное число с плавающей точкой). | {val:float} |
| guid | Тип Guid. | {val:guid} |
| int | 32-битное целое число. | {val:int} |
| length | Позволяет указать точную длину строки или ее диапазон. | {val:length(8)} {val:length(3,6)} |
| long | 64-битное целое число. | {val:long} |
| max | Максимальное значение параметра. | {val:max(16)} |
| maxlength | Максимальная длина строки. | {val:maxlength(8)} |
| min | Минимальное значение параметра. | {val:min(10)} |
| minlength | Минимальная длина строки. | {val:minlength(6)} |
| range | Устанавливает диапазон. | {val:range(10,20)} |
| regex | Задает регулярное выражение, которому должно соответствовать значение. | {val:regex(^\d{3}-\d{3}-\d{4}$)} |
Ограничитель отделяется от имени параметра двоеточием, Например, вот указание что id должен быть только целым числом:
[Route("View/{id:int}")]
public async Task<ActionResult> View(int id) { ... }
Также можно указать несколько ограничений (в примере – целое числа не меньше 1):
[Route("View/{id:int:min(1)}")]
public async Task<ActionResult> View(int id) { ... }
Если параметр является опциональным, то символ ”?” ставится после ограничителей:
[Route("View/{id:int:min(1)?}")]
public async Task<ActionResult> View(int? id) { ... }
Собственные ограничение типа значений параметров
Разработчик может создать собственные ограничения. Для этого необходимо реализовать интерфейс IRouteConstraint.
public class MyConstraint : IRouteConstraint
{
private readonly int _param;
public MyConstraint(int param)
{
this._param = param;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
...
}
}
Метод Match() должен вернуть true, если значение удовлетворяет необходимым условиям.
Остается зарегистрировать созданное ограничение и его имя в методе RegisterRoutes().
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
var constraintsResolver = new DefaultInlineConstraintResolver();
constraintsResolver.ConstraintMap.Add("myConstraint", typeof(MyConstraint));
routes.MapMvcAttributeRoutes(constraintsResolver);
}
}
После этого можно использовать его в атрибутах маршрутизации:
[Route("View/{id:myConstraint(42)")]
public async Task<ActionResult> View(int id) { ... }
Имена маршрутов
Атрибуты позволяют определять имена для маршрутов с помощью параметра Name. Такой подход может быть полезен для упрощения поддержки проекта. Например, установим имя HomePage для главной страницы сайта:
public class HomeController : Controller
{
[Route("", Name = "HomePage")]
public async Task<ActionResult> Index() { ... }
}
Теперь все ссылки на нее можно задавать следующим образом:
<a href="@Url.RouteUrl("HomePage")">Home</a>
А теперь сделаем так, что бы главной страницей был список книг. Все что надо сделать – это переместить имя на нужное действие:
public class BooksController : Controller
{
[Route("Books/Catalog/", Name = "HomePage")]
public async Task<ActionResult> Catalog() { ... }
}
Ссылки на страницах обновятся автоматически.