Атрибуты маршрутизации в Web API

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

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

В Web API также, как и в MVC, доступна такая возможность, как атрибуты маршрутизации. В прошлых темах мы рассмотрели базовый механизм обработки запросов в Web API на примере приложения, которое позволяло выполнять стандартные операции чтения, добавления, обновления и удаления объектов. Все эти операции соответствуют определенному методу протокола HTTP. Но что если мы захотим определить дополнительные методы, которые работают с определенными данными? Например, в прошлой теме рассматривалась модель Book, в которой определено свойство для хранения авторов:

public class Book
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Author { get; set; }
    public int Year { get; set; }
}

Метод получения всех авторов в контроллере Web API мог бы выглядеть таким образом:

public class ValuesController : ApiController
{
    BookContext db = new BookContext();

    public IEnumerable<Book> GetBooks()
    {
        return db.Books;
    }
    
	public IEnumerable<string> GetAuthors()
    {
        return db.Books.Select(b => b.Author).Distinct();
    }
	//остальные методы
}

Однако если бы мы запустили приложение, то браузер нам бы отобразил ошибку, поскольку у нас два метода GetBooks и GetAuthors могут обрабатывать запросы GET. И система маршрутизации не сможет определить, какой именно метод выбрать. В этом случае нам надо указать дополнительный маршрут для сопоставления с новым методом. Для этого мы можем использовать, например, введенные в MVC5 атрибуты маршрутизации:

[Route("api/values/authors")]   
public IEnumerable<string> GetAuthors()
{
    return db.Books.Select(b => b.Author).Distinct();
}

Теперь мы можем получить всех авторов с помощью запроса api/values/authors, а стандартный запрос api/values/ будет обращаться к первому методу get.

В отношении методов Web API действует та же логика атрибутов маршрутизации, что и по отношению к обычным контроллерам MVC. Подобным образом можно определить, например, метод, который будет получать автора по определенной id книги:

[Route("api/values/{id}/author")]
public string GetAuthor(int id)
{
    Book b = db.Books.Find(id);
    if (b != null)
        return b.Author;
    return "";
}

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

В определении сегмента id мы использовали ограничение, чтобы явно указать, что этот сегмент должен представлять целое число: id:int. Кроме int мы можем задать еще ряд ограничений по типу:

  • alpha: соответствует только алфавитным символам латинского алфавита. Например, {id:alpha}

  • bool: соответствует логическлму значению. Например, {id:bool}

  • datetime: соответствует значению DateTime. Например, {id:datetime}

  • decimal: соответствует значению decimal. Например, {id:decimal}

  • double: соответствует значению double. Например, {id:double}

  • float: соответствует значению float. Например, {id:float}

  • length: соответствует строке определенной длины, либо ее длина должна быть в определенном диапазоне. Например, {id:length(5)} или {id:length(5, 15)}

  • long: соответствует значению long. Например, {id:long}

  • max: соответствует значению int, которое не больше значения max. Например, {id:max(99)}. Аналогичным образом действует ограничение min, только оно указывает на минимально допустимое значение сегмента.

  • maxlength: соответствует строке, длина которой не больше определенного значения. Например, {id:maxlength(20)}. Аналогичным образом работает ограничение minlength, указывая на минимально допустимую длину строки

  • range: указывает на диапазон, в пределах которого должно находиться значение сегмента. Например, {id:range(5, 20)}

  • regex: соответствует регулярному выражению. Например, {id:regex(^\d{3}-\d{3}-\d{4}$)}

Значения по умолчанию

Как и при определении маршрута, мы можем задать значения для параметров по умолчанию:

[Route("{id:int}/{name=volga}")]
public string Test(int id, string name)
{
    return id.ToString() + ". " + name;
}

Так, если строка запроса не будет содержать последний параметр, то вместо него будет использоваться строка "volga".

Использование префиксов

Выше приводился пример атрибута маршрутизации с название контроллера в начале: [Route("Home/{id:int}/{name}")]. Но если у нас вдруг есть несколько подобных действий, обращение к которым должно начинаться с "Home", то удобно использовать префиксы:

[RoutePrefix("home")]
public class HomeController : ApiController
{
    [Route("{id:int}/{name}")]
    public string Test(int id, string name)
    {
        return id.ToString() + ". " + name;
    }
	[Route("{id:int}")]
    public string Sead(int id)
    {
        return id.ToString();
    }
	[Route("~/lol/twit/{id:int}")]
    public string Twit(int id)
    {
        return id.ToString();
    }
}

Теперь запрос к обоим методам должен начинаться с Home: "Home/5/fds" или "Home/5". При этом префикс не обязательно должен совпадать с именем контроллера, а может иметь любое значение.

Последний маршрут устраняет действие префикса с помощью знака тильды (~) в начале маршрута. И чтобы к этому методу обратиться, надо будет использовать запрос http://localhost:6392/lol/twit/2.

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