Ограничения маршрутов

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 29.10.2015

Итак, в прошлой теме были определены два маршрута:

public static class WebApiConfig
{
	public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

		config.Routes.MapHttpRoute(
            name: "ActionRoute",
            routeTemplate: "api/{controller}/{action}"
        );
		
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Пусть у нас есть оба метода, которые обрабатывают запросы GET и соответствуют обоим маршрутам:

public class ValuesController : ApiController
{ 
    public string GetValue()
    {
        return "getvalue";
    }
	public string Get(int id)
    {    
        return "id: " + id.ToString();
    }
}

Но в данном случае работать будет только один из них, а именно первый метод - GetValue. И если мы обратимся к приложению с запросом api/values/3, то естественно получим ошибку.

Дело в том, что все маршруты регистрируются в порядке определения, и первым в коллекции маршрутов в данном случае будет маршрут "ActionRoute". При поступлении запроса система маршрутизации берет первый соответствующий запросу маршрут. Так как первым будет стоять "ActionRoute", то он и будет обрабатывать как запрос api/values/getvalue, так и запрос api/values/3

Почему первый маршрут будет обрабатывать также и второй запрос? Дело в том, что запрос api/values/3 также соответствует шаблону api/{controller}/{action}. В данном случае сегмент {controller} сопоставляется со значением "values", а сегмент {action} со значением "3". Но естественно у нас нет в контроллере метода с названием "3", поэтому приложение возвратит ошибку. Чтобы избавиться от ошибки, мы можем использовать ограничения.

Ограничения маршрутов позволяют более точно настроить применение маршрутов. Web API предоставляет набор встроенных ограничений:

  • AlphaRouteConstraint: запрос соответствует маршруту, если сегмент, к которому применяется ограничение, состоит только из алфавитных символов

  • BoolRouteConstraint: запрос соответствует маршруту, если сегмент, к которому применяется ограничение, имеет значение true или false

  • DateTimeRouteConstraint: запрос соответствует маршруту, если сегмент предоставляет объект DateTime

  • DecimalRouteConstraint: запрос соответствует маршруту, если сегмент предоставляет объект decimal

  • DoubleRouteConstraint: запрос соответствует маршруту, если сегмент предоставляет объект double

  • FloatRouteConstraint: запрос соответствует маршруту, если сегмент предоставляет объект float

  • IntRouteConstraint: запрос соответствует маршруту, если сегмент предоставляет объект int

  • LongRouteConstraint: запрос соответствует маршруту, если сегмент предоставляет объект long

  • HttpMethodConstraint: маршрут соответствует запросам только определенного типа (GET, POST)

  • MaxLengthRouteConstraint / MinLengthRouteConstraint: определяют максимальную и минимальную длину сегмента в символах

  • MaxRouteConstraint / MinRouteConstraint: определяют максимальное и минимальное числовое значение для сегмента

  • RangeRouteConstraint: запрос соответствует маршруту, если сегмент предоставляет числовое значение int в определенном диапазоне

  • RegexRouteConstraint: задает регулярное значение, которому должен соответствовать сегмент

Используем ограничения, чтобы решить проблему сопоставления маршрутов, обозначенную в начале темы:

using System.Web.Http.Routing.Constraints;

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

		config.Routes.MapHttpRoute(
            name: "ActionRoute",
            routeTemplate: "api/{controller}/{action}",
            defaults: new { },
            constraints: new
            {
                action = new AlphaRouteConstraint()
            }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new {},
            constraints: new
            {
                id = new IntRouteConstraint()
            }
        );
    }
}

Поскольку в первом маршруте метод должен состоять из алфавитных символов, то к нему применяется ограничение AlphaRouteConstraint. Так как значения по умолчанию здесь нам не нужны, то мы оставляем параметр defaults: new { } пустым.

Во-втором случае параметр id должен представлять число, поэтому к нему применяется ограничение IntRouteConstraint.

Создание своих ограничений

Все классы ограничений являются реализациями интерфейса IHttpRouteConstraint, расположенного в пространстве имен System.Net.Http:

public interface IHttpRouteConstraint 
{
	bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
				IDictionary<string, object> values, HttpRouteDirection routeDirection);
}

Интерфейс IHttpRouteConstraint определяет метод Match, который принимает следующие параметры:

  • request: данные запроса в виде объекта HttpRequestMessage

  • route: объект маршрута IHttpRoute, который используется для обработки запроса

  • values: словарь, содержащий наборы пар "название параметра - ограничение параметра"

  • routeDirection: объект HttpRouteDirection указывает, должен ли маршрут применяться к входящим запросам или используется для генерации исходящих ссылок URL

И чтобы создать свое ограничение, нам надо реализовать данный интерфейс. Добавим в проект специальную папку. Назовем ее, например, Util. И добавим в нее новый класс CustomConstraint:

using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http.Routing;

namespace WebApiApp.Util
{
    public class CustomConstraint: IHttpRouteConstraint 
    {
        private string uri;
        public CustomConstraint(string uri)
        {
            this.uri = uri;
        }
        public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,  
            IDictionary<string, object> values, HttpRouteDirection routeDirection) 
        {
            return !(uri == request.RequestUri.AbsolutePath);
        }
    }
}

В данном случае в конструктор класс принимает некоторый путь, который не должен совпадать с запрошенным ресурсом. И если он не совпадает, то метод Match возвращает true.

Применим ограничение к маршруту:

config.Routes.MapHttpRoute(
    name: "ActionRoute",
    routeTemplate: "api/{controller}/{action}",
    defaults: new {},
    constraints: new
    {
        action = new AlphaRouteConstraint(),
        myConstraint = new CustomConstraint("/api/values/get")
    }
);

Теперь все запросы "/api/values/get" будут игнорироваться.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850