Результаты методов. HttpResponseMessage и IHttpActionResult

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

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

Методы контроллеров в Web API 2 могут возвращать различные типы:

  • void: просто возвращает клиенту статусный код HTTP 204

  • HttpResponseMessage: если метод возвращает объект HttpResponseMessage, то Web API преобразует возвращаемое значение в текст ответа HTTP

  • IHttpActionResult: реализация этого интерфейса позволяет составить объекты, которые реализуют различные сценарии при обработке запроса

  • любой другой тип: объекты любого другого типа сериализуются и добавляются в тело ответа, который также несет статусный код 200 (ОК)

HttpResponseMessage

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, а с помощью параметров метода можно установить опции ответа, как в данном случае код ответа и модель, которая передается клиенту.

IHttpActionResult

В 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);
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850