Чому я повинен використовувати IHttpActionResult замість HttpResponseMessage?


326

Я розвивався з WebApi і перейшов до WebApi2, де Microsoft представила новий IHttpActionResultінтерфейс, який, здається, рекомендується використовувати при поверненні HttpResponseMessage. Я плутаю переваги цього нового інтерфейсу. Здається, в основному просто надати ЛЕГКО простіший спосіб створити HttpResponseMessage.

Я б зробив аргумент, що це "абстракція заради абстракції". Я щось пропускаю? Які переваги в реальному світі я отримую від використання цього нового інтерфейсу, окрім можливо збереження рядка коду?

Старий шлях (WebApi):

public HttpResponseMessage Delete(int id)
{
    var status = _Repository.DeleteCustomer(id);
    if (status)
    {
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
    else
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
}

Новий шлях (WebApi2):

public IHttpActionResult Delete(int id)
{
    var status = _Repository.DeleteCustomer(id);
    if (status)
    {
        //return new HttpResponseMessage(HttpStatusCode.OK);
        return Ok();
    }
    else
    {
        //throw new HttpResponseException(HttpStatusCode.NotFound);
        return NotFound();
    }
}

Я просто знайшов щось цікаве. Я не впевнений, чи зможе ці результати перевірити хтось інший. Але продуктивність значно покращилася, коли я робив дзвінки: * На прикладі використання HttpResponseMessageя отримав відповідь ще в 9545 мс . * Використовуючи IHttpActionResultI, я отримав таку ж відповідь ще за 294 мс .
лізинг Кріса

@chrislesage 9545 мс майже 10 секунд. Навіть 294 мс - це повільно. Якщо у вас є щось, що займає більше 100 мс, то там ще щось працює. У цій історії є більше, ніж зустрічається з їжею.
AaronLS

Відповіді:


305

Ви можете вирішити не використовувати, IHttpActionResultоскільки ваш існуючий код створює HttpResponseMessageте, що не відповідає одному із консервованих відповідей. Однак ви можете пристосуватися HttpResponseMessageдо IHttpActionResultвикористання консервованої відповіді ResponseMessage. Щоб розібратися в цьому, мені знадобилося деякий час, тому я хотів опублікувати його, показуючи, що вам не потрібно вибирати те чи інше:

public IHttpActionResult SomeAction()
{
   IHttpActionResult response;
   //we want a 303 with the ability to set location
   HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.RedirectMethod);
   responseMsg.Headers.Location = new Uri("http://customLocation.blah");
   response = ResponseMessage(responseMsg);
   return response;
}

Зауважте, ResponseMessageце метод базового класу ApiController, від якого повинен успадкувати ваш контролер.


1
Зайняв мене час, щоб дізнатися, що ResponseMessage зараз ResponseMessageResult. Можливо, його перейменовано нещодавно? PS Ви також пропустили нове ключове слово у відповіді і велике спасибі за пропозицію :)
Ілля Черномордик

10
@IlyaChernomordik ResponseMessageі ResponseMessageResultце дві різні речі. ResponseMessage()це метод, від ApiControllerякого повинен успадкувати ваш контролер, і тому це лише виклик методу. Тому newключове слово там не потрібно. Ви, мабуть, не успадковуєте ApiControllerабо перебуваєте у статичному методі. ResponseMessageResult- це тип повернення ResponseMessage().
AaronLS

3
@IlyaChernomordik Я міг би написати, response = base.ResponseMessage(responseMsg)щоб зрозуміти, що це метод базового класу ApiController
AaronLS

Дякую, у мене справді був сервіс, який не успадкував від ApiController, тому знадобився певний час, щоб знайти.
Ілля Чорномордик

3
@pootzko Ви маєте рацію, я звернувся до того факту, що ОП, здавалося, передбачає, що вони вважають, що два підходи взаємно виключають, обрамляючи це як "старий шлях" проти "новий шлях", коли насправді вони не є. Я думаю, що відповідь Даррела добре допомагає пояснити деякі переваги повернення IHttpActionResult, і моя відповідь демонструє, як ви можете перетворити старий HttpResponseMessage в IHttpActionResult, щоб ви мали найкращі з обох світів.
AaronLS

84

Ви все ще можете використовувати HttpResponseMessage. Ця здатність не зникне. Я почував себе так само, як і ви, і наполегливо сперечався з командою, що немає необхідності в додатковій абстракції. Кілька аргументів було викинуто, щоб спробувати виправдати його існування, але нічого, що переконувало мене, було варте.

Тобто, поки я не побачив цей зразок від Бреда Вілсона . Якщо ви будуєте IHttpActionResultкласи таким чином, щоб їх можна було пов'язати ланцюжком, ви отримуєте можливість створити конвеєр відповідей на рівні дії для генерації HttpResponseMessage. Під обкладинками так ActionFiltersреалізовано, але впорядкування їх ActionFiltersне очевидно при читанні методу дій, що є однією з причин, що я не прихильник фільтрів дій.

Однак, створивши метод, IHttpActionResultякий може бути явно пов'язаний у вашому методі дій, ви можете скласти всі види різної поведінки для створення вашої відповіді.


62

Ось кілька переваг IHttpActionResultнад HttpResponseMessageзгаданим в Microsoft ASP.Net документації :

  • Спрощує блок тестування контролерів.
  • Переміщує загальну логіку для створення відповідей HTTP в окремі класи.
  • Зрозуміє наміри дії контролера більш чіткими, приховуючи деталі низького рівня побудови відповіді.

Але ось деякі інші переваги використання IHttpActionResultварто згадати:

  • Поважаючи принцип єдиної відповідальності : спричиняйте, що методи дій нестимуть відповідальність за обслуговування HTTP-запитів, а не залучайте їх до створення повідомлень відповідей HTTP.
  • Корисні реалізації, вже визначені в System.Web.Http.Results, а саме: Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState( посилання на повний список )
  • За замовчуванням використовує функцію Async та Await .
  • Легко створити власний ActionResult просто методом реалізації ExecuteAsync.
  • ви можете використовувати ResponseMessageResult ResponseMessage(HttpResponseMessage response)для перетворення HttpResponseMessage в IHttpActionResult .


18

Це лише моя особиста думка, і люди з команди веб-API можуть, мабуть, сформулювати це краще, але ось мій 2с.

Перш за все, я думаю, що це не питання один над одним. Ви можете використовувати їх як в залежності від того, що ви хочете зробити в методі дії , але для того , щоб зрозуміти реальну силу IHttpActionResult, вам, ймовірно , потрібно вийти за межі цих зручних допоміжних методів в ApiControllerтаких як Ok, NotFoundі т.д.

В основному, я думаю, що клас реалізується IHttpActionResultяк фабрика HttpResponseMessage. З урахуванням цього розуму він стає об'єктом, який потрібно повернути, і заводом, який його виробляє. У загальному сенсі програмування ви можете створити об’єкт самостійно в певних випадках, а в певних випадках для цього вам потрібна фабрика. Те ж саме.

Якщо ви хочете повернути відповідь, яку потрібно побудувати за допомогою складної логіки, скажімо, багато заголовків відповідей тощо, ви можете абстрагувати всю цю логіку до класу результатів дії, реалізуючи IHttpActionResultі використовувати її в декількох методах дій для повернення відповіді.

Ще однією перевагою використання IHttpActionResultяк типу повернення є те, що він робить метод дій ASP.NET Web API подібним до MVC. Ви можете повернути будь-який результат дії, не потрапляючи в медіаформатори.

Звичайно, як зазначає Даррел, ви можете ланцюжок результатів дій і створити потужний мікропровід, подібний до самих обробників повідомлень у API-конвеєрі. Це вам знадобиться залежно від складності способу вашої дії.

Довга коротка історія - це не IHttpActionResultпроти HttpResponseMessage. В основному, це те, як ви хочете створити відповідь. Зробіть це самостійно або через фабрику.


Проблема, яку я мав із заводським підтвердженням, полягає в тому, що я можу легко створювати статичні методи, такі як ResponseFactory.CreateOkResponse()повернення HttpResponseMessage, і мені не довелося мати справу з асинхронними матеріалами при створенні відповіді. Один з членів команди згадав той факт, що асинхроніка може бути корисною, якщо вам потрібно зробити введення / виведення, щоб генерувати значення заголовка. Не впевнений, як часто це відбувається, хоча.
Даррел Міллер

Я думаю, це те саме, що говорити, навіщо нам потрібна фабрична схема методу. Чому б просто не використовувати статичні методи для створення об'єктів. Звичайно, це можливо - кожне створення об'єкта не є належним заводським зразком. Але тоді IMHO залежить від того, як ви хочете моделювати свої класи. Ви хочете мати логіку для створення різних типів відповідей, всі набиваються до класу у вигляді декількох статичних методів або мають різні класи на основі інтерфейсу. Знову ж таки, немає ні хорошого, ні поганого. Все залежить. У будь-якому разі, моя думка полягає в тому, що це не одна над одною, і мені особисто більше подобається фабрична річ :)
Badri

6

Web API в основному повертає 4 типу об'єкта: void, HttpResponseMessage, IHttpActionResult, та інші сильні тип. Перша версія Web API повертається, HttpResponseMessageщо є досить прямим повідомленням HTTP-відповіді.

Це IHttpActionResultбуло запроваджено WebAPI 2, який є своєрідною обробкою HttpResponseMessage. Він містить ExecuteAsync()метод створення HttpResponseMessage. Це спрощує тестування пристрою вашого контролера.

Інший тип повернення - це набір сильних типових класів, серіалізованих за допомогою Web API за допомогою медіаформатора в тіло відповідей. Недоліком було те, що ви не можете безпосередньо повернути код помилки, наприклад, 404. Все, що ви можете зробити - це викинути HttpResponseExceptionпомилку.


3

Я б швидше реалізував функцію інтерфейсу TaskExecuteAsync для IHttpActionResult. Щось на зразок:

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = _request.CreateResponse(HttpStatusCode.InternalServerError, _respContent);

        switch ((Int32)_respContent.Code)
        { 
            case 1:
            case 6:
            case 7:
                response = _request.CreateResponse(HttpStatusCode.InternalServerError, _respContent);
                break;
            case 2:
            case 3:
            case 4:
                response = _request.CreateResponse(HttpStatusCode.BadRequest, _respContent);
                break;
        } 

        return Task.FromResult(response);
    }

, де _request - HttpRequest, а _respContent - корисна навантаження.


2

Ми маємо наступні переваги використання IHttpActionResultбільш HttpResponseMessage:

  1. Використовуючи IHttpActionResultми, ми зосереджуємося лише на даних, що надсилаються, а не на код статусу. Тож тут код буде більш чистим і дуже простим у обслуговуванні.
  2. Тестування блоку реалізованого методу контролера буде простішим.
  3. Використовує asyncі awaitза замовчуванням.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.