ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

Как работают API контроллеры

Чтобы больше узнать о том, как работает контроллер API, перейдите по ссылке /api/reservation/3. Вы увидите следующий JSON (или соответствующий XML, если вы используете другой браузер):

{"ReservationId":3,"ClientName":"Jacqui","Location":"Paris"}

На этот раз наш запрос вернул информацию об объекте Reservation, значение ReservationId которого соответствует последнему сегменту URL. Формат URL и использование сегментов URL должны напомнить вам о главе 13, в которой объяснялись принципы работы маршрутов в MVC Framework.

В контроллерах API есть своя конфигурация маршрутизации, которая полностью отделена от всего остального приложения. Конфигурацию по умолчанию, которую Visual Studio создает для новых проектов, можно увидеть в файле /App_Start/WebApiConfig.cs, который показан в листинге 25-9 .

Листинг 25-9: Содержимое файла WebApiConfig.cs по умолчанию
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace WebServices
{
	public static class WebApiConfig
	{
		public static void Register(HttpConfiguration config)
		{
			config.Routes.MapHttpRoute(
				name: "DefaultApi",
				routeTemplate: "api/{controller}/{id}",
				defaults: new {id = RouteParameter.Optional}
				);
		}
	}
}

Файл WebApiConfig.cs содержит маршруты, которые используются контроллерами API, но обычные маршруты MVC, которые определены в файле RouteConfig.cs, в нем не используются. Функция Web API реализована как автономная функция ASP.NET, ее можно использовать вне MVC Framework, следовательно, Microsoft дублировала ключевую функциональность MVC Framework из пространства имен System.Web.Http, чтобы отделить Web API от MVC. (Это кажется странным при разработке приложения в MVC Framework, но все же имеет смысл, поскольку Microsoft позволяет использовать Web API разработчикам, которые не работают с MVC).

При запуске приложения вызывается статический метод Register из метода Application_Start файла Config.asax; этот метод используется для регистрации маршрутов Web API. Метод Register получает объект HttpConfiguration, который предоставляет доступ к маршрутизации через свойство Routes. Маршруты создаются с помощью метода MapHttpRoute.

Принцип выбора действий в контроллере API

Стандартный маршрут Web API, который показан в листинге 25-9, содержит статический сегмент api и переменные сегментов controller и id, причем последний является дополнительным. Ключевым отличием от обычного маршрута MVC является то, что в нем нет переменной сегмента action; с этого момента поведение контроллеров API будет более понятным.

Когда в приложение поступает запрос, соответствующий маршруту Web API, действие определяется по методу HTTP, который использовался в запросе. Когда мы проверили работу контроллера API, перейдя по ссылке /api/reservation, браузер указал метод GET.

Класс ApiController, который является основой контроллеров API, узнает из маршрута, какой контроллер должен обрабатывать запрос, и использует метод HTTP для поиска подходящих методов действий. По соглашению методы действий контроллеров API должны содержать приставку с именем метода действия, который они поддерживают, и тип модели, с которым они работают. Но это только соглашение, поскольку Web API найдет любой метод действия, в имени которого указан метод HTTP, использовавшийся в запросе.

В нашем примере это означает, что для запроса GET выбор будет проводиться между GetAllReservations и GetReservation, но если бы методы назывались DoGetReservation или просто ThisIsTheGetAction, они бы тоже учитывались.

Чтобы выбрать между двумя методами действий, контроллер смотрит на аргументы, которые принимают контроллеры, и переменные маршрутизации. При запросе API по ссылке /api/reservation, в которой нет переменных маршрутизации за исключением controller, был выбран метод GetAllReservations, потому что он не принимает аргументов. Когда мы запросили URL /api/reservation/3, мы поставили значение для опциональной переменной сегмента id; для этого запроса лучше подходит метод GetReservation, потому что он принимает аргумент id.

Для вызова других действий в нашем контроллере API Reservation будут использоваться другие методы HTTP: POST, DELETE и PUT. Это служит основой стиля REST (Representation State Transfer) Web API, также известного как REST-сервис, в котором операция определяется комбинацией URL и метода HTTP, использованного в запросе к данному URL.

Примечание

REST является стилем API, а не четко определенной спецификацией, поэтому существуют разногласия по поводу того, что именно делает веб-службу REST-сервисом. Одной из точек разногласий является то, что «пуристы» не считают веб-службы, которые возвращают JSON, REST-сервисами. Как и все споры по поводу архитектурных шаблонов, этот возник из-за скучных и несерьезных причин. Мы рассматриваем применение шаблонов с практической стороны и убеждены, что сервисы JSON являются REST-сервисами.

Соотнесение методов HTTP с методами действий

Как мы уже объяснили, базовый класс ApiController использует метод HTTP, чтобы узнать, какой метод действий должен обрабатывать запрос. Это хороший подход, но он означает, что вам придется назначать методам действий неестественные имена, противоречащие соглашениям, которые вы могли бы использовать в приложении. Например, метод PutReservation более естественно было бы назвать UpdateReservation. Имя UpdateReservation не только сделало бы цель метода более очевидной, но и позволило бы напрямую соотносить действия контроллера и методы хранилища.

Подсказка

Вы могли бы попытаться наследовать класс хранилища от ApiController и использовать методы хранилища напрямую как Web API. Мы настоятельно не рекомендуем так делать и советуем создавать отдельный контроллер, даже если он будет таким же простым, как в нашем примере. В какой-то момент методы, которые вы захотите использовать в API, и возможности хранилища начнут отличаться, и отдельный контроллер API упростит решение этой проблемы.

Пространство имен System.Web.Http содержит набор атрибутов, с помощью которых можно указать, для какого метода HTTP должно использоваться действие. В листинге 25-10 показано, как мы применили два из этих атрибутов, чтобы создать более естественные имена методов.

Листинг 25-10: Указываем методы HTTP, которые поддерживает действие, с помощью атрибутов
using System.Collections.Generic;
using System.Web.Http;
using WebServices.Models;

namespace WebServices.Controllers
{
	public class ReservationController : ApiController
	{
		private IReservationRepository repo = ReservationRepository.getRepository();

		public IEnumerable<Reservation> GetAllReservations()
		{
			return repo.GetAll();
		}

		public Reservation GetReservation(int id)
		{
			return repo.Get(id);
		}

		[HttpPost]
		public Reservation CreateReservation(Reservation item)
		{
			return repo.Add(item);
		}

		[HttpPut]
		public bool UpdateReservation(Reservation item)
		{
			return repo.Update(item);
		}

		public void DeleteReservation(int id)
		{
			repo.Remove(id);
		}
	}
}

Вы можете заметить, что в Web API дублируются функции MVC Framework, которые мы рассмотрели в главе 17. Атрибуты HttpPost и HttpPut, которые мы использовали в листинге 25-10, имеют точно такую же цель, что и одноименные атрибуты в главе 17, но они определены в пространстве имен System.Web.Http, а не System.Web.Mvc. Эти атрибуты работают таким же образом, и в итоге мы получили более полезные имена методов, которые будут работать с HTTP-методами POST и PUT. (Конечно, существуют атрибуты для всех методов HTTP, в том числе GET, DELETE и т.д.)

или RSS канал: Что новенького на smarly.net