При обработке запроса система маршрутизации на основании шаблон маршрута автоматически извлекает из строки запроса значения для параметров маршрута вне зависимости от содержимого этих значений. Однако это не всегда бывает удобно. Например, мы хотим, чтобы какой-то параметр представлял только числа, а другой параметр начинался строго с определенного символа. И для этого необходимо задать ограничения маршрута (route constraints).
Ограничения маршрутов выполняюся при парсинге пути запроса, сопоставлении его с шаблоном маршрута и выделении из него значений для параметров маршрута. Ограничения маршрутов применяются для разных задач. Прежде всего они решают, допустимо ли для параметра маршрута значение, которое выделено из пути запроса. Также ограничения маршрута могут решать, можно ли вообще сопоставить путь запроса с определенным маршрутом. Кроме того, ограничения маршрута могут применяться при генерации ссылок.
Вначале рассмотрим следующую ситуацию. Пусть у нас есть следующее приложение:
var builder = WebApplication.CreateBuilder(); var app = builder.Build(); app.Map("/users/{id}", (int id) => $"User Id: {id}"); app.Map("/", () => "Index Page"); app.Run();
Первая конечная точка использует маршрут, который подразумевает наличие параметра id
. А в обработчике маршрута мы хотим получить значение этого параметра в виде числа.
То есть мы ожидаем, что в пути запроса будет передаваться число, например, "/users/123". Тем не менее мы можем передать вместо числа и строку:
На скриншоте выше обращение идет по адресу "/users/hello". И этот путь запроса в принципе соответствует шаблону маршрута "/users/{id}". В этом случае
параметр маршрута id
получит значение "hello", а для обработки запроса будет запущено действие
(int id) => $"User Id: {id}";
Однако параметр id обработчика представляет тип int
, а строка "hello" никак не может быть конвертирована в число. Соответственно мы получим ошибку при преобразовании,
о чем собственно и говорит скриншот.
Теперь применим ограничения - укажем, что параметр id в маршруте должен представлять тип int
:
var builder = WebApplication.CreateBuilder(); var app = builder.Build(); app.Map("/users/{id:int}", (int id) => $"User Id: {id}"); app.Map("/", () => "Index Page"); app.Run();
Для установки ограничения после названия параметра через двоеточие указывается название ограничения. Ограничение int
указывает, что параметр должен
представлять тип int.
В этом случае нам надо передать этому параметру число:
Да, мы по-прежнему можем передавать в пути запроса строку вместо числа:
Но в этом случае инфраструктура ASP.NET Core просто не сможет сопоставить данный путь запроса с шаблоном маршрута. И клиент получит ошибку 404, то есть ресурс не найден.
ASP.NET Core предоставляет следующий ряд ограничений маршрута:
int
Соответствие целому числу. Представляет класс IntRouteConstraint
{id:int}
bool. Представляет класс BoolRouteConstraint
Соответствие значению true или false
{active:bool}
datetime
Соответствие дате и времени. Представляет класс DateTimeRouteConstraint
{date:datetime}
decimal
Соответствие значению decimal. Представляет класс DecimalRouteConstraint
{price:decimal}
double
Соответствие значению типа double. Представляет класс DoubleRouteConstraint
{weight:double}
float
Соответствие значению типа float. Представляет класс FloatRouteConstraint
{height:float}
guid
Соответствие значению типа Guid. Представляет класс GuidRouteConstraint
{id:guid}
long
Соответствие значению типа long. Представляет класс LongRouteConstraint
{id:long}
minlength(value)
Строка должна иметь символов не меньше value. Представляет класс MinLengthRouteConstraint
{name:minlength(3)}
maxlength(value)
Строка должна иметь символов не больше value. Представляет класс MaxLengthRouteConstraint
{name:maxlength(20)}
length(value)
Строка должна иметь ровно столько символов, сколько определено в параметре value. Представляет класс LengthRouteConstraint
{name:length(10)}
length(min, max)
Строка должна иметь символов не меньше min и не больше max. Представляет класс LengthRouteConstraint
{name:length(3, 20)}
min(value)
Число должно быть не меньше value. Представляет класс MinRouteConstraint
{age:min(3)}
max(value)
Число должно быть не больше value. Представляет класс MaxRouteConstraint
{age:max(20)}
range(min, max)
Число должно быть не меньше min и не больше max. Представляет класс RangeRouteConstraint
{age:range(18, 99)}
alpha
Строка должна состоять из одного и более алфавитных символов. Представляет класс AlphaRouteConstraint
{name:alpha}
regex(expression)
Строка должна соответствовать регулярному выражению expression. Представляет класс RegexRouteConstraint
{phone:regex(^\d{{3}}-\d{{3}}-\d{{4}}$)}
required
Параметр является обязательным, и его значение должно быть определено. Представляет класс RequiredRouteConstraint
{name:required}
Каждое подобное ограничени представляет определенный класс. Все классы ограничений находятся в пространстве имен Microsoft.AspNetCore.Routing.Constraints
Ограничения можно комбинировать. При применении нескольких ограничений одновременно, они отделяются друг о друга двоеточием Например:
var builder = WebApplication.CreateBuilder(); var app = builder.Build(); app.Map( "/users/{name:alpha:minlength(2)}/{age:int:range(1, 110)}", (string name, int age) => $"User Age: {age} \nUser Name:{name}" ); app.Map( "/phonebook/{phone:regex(^7-\\d{{3}}-\\d{{3}}-\\d{{4}}$)}/", (string phone) => $"Phone: {phone}" ); app.Map("/", () => "Index Page"); app.Run();
Первая конечная точка использует шаблон маршрута
"/users/{name:alpha:minlength(2)}/{age:int:range(1, 110)}"
Здесь предполагается, что параметр name
принимает только алфавитные символы, а его минимальная длина должна представлять два символа.
Второй же параметр маршрута - age
должен представлять целое число и должен находиться в диапазоне между 1 и 110:
Вторая конечная точка использует шаблон маршрута
"/phonebook/{phone:regex(^7-\\d{{3}}-\\d{{3}}-\\d{{4}}$)}"
Параметр phone
принимает номер телефона в формате 7-ххх-ххх-хххх, любые другие форматы будут некорректными: