Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Методы контроллеров в Web API 2 могут возвращать различные типы:
void: просто возвращает клиенту статусный код HTTP 204
HttpResponseMessage: если метод возвращает объект HttpResponseMessage, то Web API преобразует возвращаемое значение в текст ответа HTTP
IHttpActionResult: реализация этого интерфейса позволяет составить объекты, которые реализуют различные сценарии при обработке запроса
любой другой тип: объекты любого другого типа сериализуются и добавляются в тело ответа, который также несет статусный код 200 (ОК)
HttpResponseMessage является основным способом для возврата результата из метода в контроллере Web API. Например, метод CreateBook, который создает и добавляет новый объект в БД, мог бы выглядеть следующим образом:
public HttpResponseMessage CreateBook([FromBody]Book book) { db.Books.Add(book); db.SaveChanges(); return new HttpResponseMessage(HttpStatusCode.Created); }
Если нам надо передать клиенту какой-либо объект, то мы можем воспользоваться типизированным варианта данного класса. Например, передадим список:
public HttpResponseMessage GetBooks() { var response = Request.CreateResponse<IEnumerable<Book>>(HttpStatusCode.OK, db.Books); return response; }
Метод Request.CreateResponse
создает объект HttpResponseMessage, а с помощью параметров метода можно установить опции ответа,
как в данном случае код ответа и модель, которая передается клиенту.
В Web API 2 был добавлен новый тип объектов, которые используются в качестве результатов методов. Этот тип представляет интерфейс IHttpActionResult. Классы, реализующие данный интерфейс, во многом аналогичны классам, производным от ActionResult в MVC.
Интерфейс IHttpActionResult имеет следующее определение:
namespace System.Web.Http { public interface IHttpActionResult { Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken); } }
Единственный метод интерфейса возвращает объект HttpResponseMessage
, который представляет собой ответ клиенту. Поэтому хотя метод и
возвращает объект IHttpActionResult, но в итоге данный объект также продуцирует HttpResponseMessage.
Мы можем как создать свой класс, реализующий данный интерфейс, так и использовать уже имеющиеся встроенные классы, которые определены в пространстве
имен System.Web.Http.Results
. Некоторые из этих классов:
OkResult возвращает ответ HttpStatusCode.OK
, то есть статусный код HTTP 200. Создается с помощью метода
Ok
без параметров
OkNegotiatedContentResult<T> возвращает статусный код HTTP 200, а также результат обработки в виде
объекта типа T. Создается с помощью метода Ok
, который в качестве параметра принимает объект, возвращаемый клиенту
NotFoundResult возвращает в ответ статусный код 404. Создается с помощью метода NotFound
ExceptionResult возвращает в ответ статусный код 500, свидетельствующий об ошибке обработки запроса.
Генерируется методом InternalServerError(Exception)
, в который передается объект с описанием ошибки
UnauthorizedResult возвращает в ответ статусный код 401, который говорит о том, что запрос должен быть
аутентифицирован. Генерируется методом Unauthorized
BadRequestResult возвращает в ответ статусный код 400. Генерируется методом BadRequest()
без параметров
JsonResult возвращает объекты в формате json. Генерируется методом Json(T content)
, который в качестве параметра
принимает некоторый объект типа T. Данный объект сериализуется в формат json и отправляет в таком виде клиенту.
RedirectResult позволяет переадресовать выполнение запроса. Генерируется методом Redirect(string path)
И если мы посмотрим, например, на контроллер, генерируемый с помощью шаблонов, то мы увидим, что там получение единичного объекта имеет примерно следующий вид:
public IHttpActionResult GetBook(int id) { Book book = db.Books.Find(id); if (book == null) { return NotFound(); } return Ok(book); }
Метод NotFound
генерирует объект NotFoundResult, который отправляет в ответ пользователю статусный код 404. А метод Ok создает
объект OkNegotiatedContentResult<T>
, который отправляет вместе со статусным кодом 200 также и результат обработки - в данном случае объект Book
К примеру метод:
public IEnumerable<Book> GetBooks() { return db.Books; }
можно было бы переписать так:
public IHttpActionResult GetBooks() { return Ok(db.Books); }
Рассмотрим еще метод для обработки Post-запросов, который создается с помощью шаблонов:
[ResponseType(typeof(Book))] public IHttpActionResult PostBook(Book book) { if (!ModelState.IsValid) { return BadRequest(ModelState); } db.Books.Add(book); db.SaveChanges(); return CreatedAtRoute("DefaultApi", new { id = book.Id }, book); }
Метод BadRequest
в данном случае возвращает объект InvalidModelStateResult
, который отправляет клиенту
статусный код 400, а также сведения об ошибке валидации модели. Если бы мы использовали перегрузку этого метода без параметров,
то он возвращал бы объект BadRequestResult
, что было бы аналогично простой отправки клиенту статусного кода 400.
Также здесь есть метод CreatedAtRoute
, который возвращает объект CreatedAtRouteNegotiatedContentResult<T>
.
Этот метод создает маршрут с помощью передаваемых в него параметров и посылает клиенту статусный код 201, который указывает, что сервер успешно создал
новый объект.
Имеющиеся классы результатов охватывают большинство возможных ситуаций. Однако при необходимости мы можем создать и свой класс, отвечающий определенным потребностям. Например, пусть результат запроса будет передаваться клиенту в виде страницы html. Для этого создадим следующий класс:
using BookingApp.Models; using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using System.Web.Http; //........................ public class HtmlContentResult : IHttpActionResult { private Book model; public HtmlContentResult(Book model) { this.model = model; } public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) { string bookInfo = "<html><head><meta charset=utf-8 /></head></body>" + "<h1>" + model.Name + "</h1><p>" + model.Author + "</p><p>" + model.Year + "</p>" + "</body></html>"; // объект ответа var response = new HttpResponseMessage(); // создаем ответ response.Content = new StringContent(bookInfo); // отмечаем, что ответ будет в виде html response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html"); return Task.FromResult(response); } }
И теперь применим этот класс для получения одного объекта по id:
public IHttpActionResult GetBook(int id) { Book book = db.Books.Find(id); return new HtmlContentResult(book); }