Маршрутизация в веб-API ASP.NET

В этой статье описывается, как ASP.NET веб-API направляет HTTP-запросы к контроллерам.

Замечание

Если вы знакомы с ASP.NET MVC, маршрутизация веб-API очень похожа на маршрутизацию MVC. Основное различие заключается в том, что веб-API использует HTTP-команду, а не путь URI для выбора действия. Вы также можете использовать маршрутизацию в стиле MVC в веб-API. В этой статье не предполагается никаких знаний о ASP.NET MVC.

Таблицы маршрутизации

В ASP.NET веб-API контроллер — это класс, который обрабатывает HTTP-запросы. Общедоступные методы контроллера называются методами действий или просто действиями. Когда платформа веб-API получает запрос, он направляет запрос в действие.

Чтобы определить, какое действие необходимо вызвать, платформа использует таблицу маршрутизации. Шаблон проекта Visual Studio для веб-API создает маршрут по умолчанию:

routes.MapHttpRoute(
    name: "API Default",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Этот маршрут определен в файле WebApiConfig.cs , который помещается в каталог App_Start :

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

Дополнительные сведения о классе см. в WebApiConfig разделе "Настройка ASP.NET веб-API".

При самостоятельном размещении веб-API необходимо задать таблицу маршрутизации непосредственно в объекте HttpSelfHostConfiguration . Дополнительные сведения см. в Самостоятельное размещение веб-API.

Каждая запись в таблице маршрутизации содержит шаблон маршрута. Шаблон маршрута по умолчанию для веб-API — api/{controller}/{id}. В этом шаблоне api — это сегмент литерального пути, а {controller} и {id} — это переменные заполнителя.

Когда платформа веб-API получает HTTP-запрос, он пытается сопоставить URI с одним из шаблонов маршрутов в таблице маршрутизации. Если маршрут не соответствует, клиент получает ошибку 404. Например, следующие URI соответствуют маршруту по умолчанию:

  • /api/contacts
  • /api/contacts/1
  • /api/products/gizmo1

Однако следующий идентификатор ресурса (URI) не соответствует, так как он не имеет сегмента "api".

  • /contacts/1

Замечание

Причина использования api в маршруте заключается в том, чтобы избежать конфликтов с маршрутизацией ASP.NET MVC. Таким образом, путь "/contacts" может вести к контроллеру MVC, а "/api/contacts" — к контроллеру Web API. Конечно, если вы не любите это соглашение, вы можете изменить таблицу маршрутов по умолчанию.

После обнаружения соответствующего маршрута веб-API выбирает контроллер и действие:

  • Чтобы найти контроллер, веб-API добавляет "Controller" в значение переменной {controller} .
  • Чтобы найти действие, веб-API смотрит на http-команду, а затем ищет действие, имя которого начинается с этого имени http-команды. Например, с запросом GET веб-API ищет действие с префиксом Get, например GetContact или GetAllContacts. Это соглашение применяется только к командам GET, POST, PUT, DELETE, HEAD, OPTIONS и PATCH. Вы можете включить другие HTTP-команды с помощью атрибутов на контроллере. Мы увидим пример этого позже.
  • Другие переменные заполнителя в шаблоне маршрута, такие как {id}, сопоставляются с параметрами действия.

Рассмотрим пример. Предположим, что вы определяете следующий контроллер:

public class ProductsController : ApiController
{
    public IEnumerable<Product> GetAllProducts() { }
    public Product GetProductById(int id) { }
    public HttpResponseMessage DeleteProduct(int id){ }
}

Ниже приведены некоторые возможные HTTP-запросы, а также действие, которое вызывается для каждого из них:

HTTP-команда Путь URI Действие Параметр
GET api/products GetAllProducts (нет)
GET api/products/4 ПолучитьПродуктПоИдентификатору 4
DELETE api/products/4 УдалитьПродукт 4
ПОСТ api/products (нет совпадения)

Обратите внимание, что сегмент URI {id} при наличии сопоставляется с параметром идентификатора действия. В этом примере контроллер определяет два метода GET, один с параметром идентификатора и один без параметров.

Кроме того, обратите внимание, что запрос POST завершится ошибкой, так как контроллер не определяет метод Post..." .

Варианты маршрутизации

В предыдущем разделе описан базовый механизм маршрутизации для ASP.NET веб-API. В этом разделе описываются некоторые варианты.

HTTP-глаголы

Вместо использования соглашения об именовании для http-команд можно явно указать HTTP-команду для действия, декорируя метод действия одним из следующих атрибутов:

  • [HttpGet]
  • [HttpPut]
  • [HttpPost]
  • [HttpDelete]
  • [HttpHead]
  • [HttpOptions]
  • [HttpPatch]

В следующем примере метод FindProduct сопоставляется с GET-запросами:

public class ProductsController : ApiController
{
    [HttpGet]
    public Product FindProduct(id) {}
}

Чтобы разрешить несколько HTTP-команд для действия или разрешить HTTP-команды, отличные от GET, PUT, POST, DELETE, HEAD, OPTIONS и PATCH, используйте [AcceptVerbs] атрибут, который принимает список HTTP-команд.

public class ProductsController : ApiController
{
    [AcceptVerbs("GET", "HEAD")]
    public Product FindProduct(id) { }

    // WebDAV method
    [AcceptVerbs("MKCOL")]
    public void MakeCollection() { }
}

Маршрутизация по имени действия

С помощью шаблона маршрутизации по умолчанию веб-API использует HTTP-команду для выбора действия. Однако можно также создать маршрут, в котором имя действия включено в универсальный код ресурса (URI):

routes.MapHttpRoute(
    name: "ActionApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

В этом шаблоне маршрута параметр {action} называет метод действия контроллера. С помощью этого стиля маршрутизации используйте атрибуты для указания разрешенных http-команд. Например, предположим, что у контроллера есть следующий метод:

public class ProductsController : ApiController
{
    [HttpGet]
    public string Details(int id);
}

В этом случае GET-запрос по адресу "api/products/details/1" будет соответствовать методу Details. Этот стиль маршрутизации аналогичен ASP.NET MVC и может быть подходящим для API в стиле RPC.

Имя действия можно переопределить с помощью атрибута [ActionName] . В следующем примере есть два действия, которые сопоставляются с "api/products/thumbnail/id". Одно поддерживает GET, а другое поддерживает POST:

public class ProductsController : ApiController
{
    [HttpGet]
    [ActionName("Thumbnail")]
    public HttpResponseMessage GetThumbnailImage(int id);

    [HttpPost]
    [ActionName("Thumbnail")]
    public void AddThumbnailImage(int id);
}

Не действия

Чтобы предотвратить вызов метода в качестве действия, используйте [NonAction] атрибут. Это сигнализирует платформе о том, что метод не является действием, даже если оно в противном случае соответствует правилам маршрутизации.

// Not an action method.
[NonAction]  
public string GetPrivateData() { ... }

Дальнейшее чтение

В этом разделе представлено высокоуровневое представление маршрутизации. Дополнительные сведения см. в разделе "Маршрутизация и выбор действия", в котором описывается точное соответствие платформы URI маршруту, выбор контроллера и выбор действия для вызова.