Mengapa saya harus menggunakan IHttpActionResult daripada HttpResponseMessage?

326

Saya telah mengembangkan dengan WebApi dan telah pindah ke WebApi2 di mana Microsoft telah memperkenalkan IHttpActionResultAntarmuka baru yang tampaknya direkomendasikan untuk digunakan daripada mengembalikan a HttpResponseMessage. Saya bingung tentang kelebihan dari Antarmuka baru ini. Tampaknya terutama hanya menyediakan cara yang sedikit lebih mudah untuk membuat HttpResponseMessage.

Saya akan mengajukan argumen bahwa ini adalah "abstraksi demi abstraksi". Apakah saya melewatkan sesuatu? Apa keuntungan dunia nyata yang saya dapatkan dari menggunakan Antarmuka baru ini selain mungkin menghemat satu baris kode?

Cara lama (WebApi):

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

Cara Baru (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();
    }
}
Jason Roell
sumber
Saya baru saja menemukan sesuatu yang menarik. Saya tidak yakin apakah hasil ini dapat diverifikasi oleh orang lain. Tetapi kinerja meningkat banyak dengan beberapa panggilan yang saya lakukan: * Dengan menggunakan contoh HttpResponseMessagesaya mendapat respons kembali di 9545 ms . * Menggunakan IHttpActionResultI mendapat respons yang sama kembali dalam 294 ms .
les chris
@ chrislesage 9545 ms hampir 10 detik. Bahkan 294ms agak lambat. Jika Anda memiliki sesuatu yang mengambil lebih dari 100 ms maka sesuatu yang lain sedang bekerja di sana. Ada lebih banyak cerita dari memenuhi ete.
AaronLS

Jawaban:

305

Anda mungkin memutuskan untuk tidak menggunakan IHttpActionResultkarena kode Anda yang ada membuat kode HttpResponseMessageyang tidak cocok dengan salah satu dari tanggapan kalengan. Namun Anda dapat beradaptasi HttpResponseMessagedengan IHttpActionResultmenggunakan respons kalengan ResponseMessage. Butuh beberapa saat untuk memikirkan ini, jadi saya ingin mempostingnya yang menunjukkan bahwa Anda tidak harus memilih satu atau yang lain:

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;
}

Catatan, ResponseMessageadalah metode kelas dasar ApiControlleryang harus diwarisi oleh pengontrol Anda.

AaronLS
sumber
1
Butuh beberapa saat untuk mengetahui bahwa ResponseMessage sekarang adalah ResponseMessageResult. Mungkin baru saja diganti namanya? PS Anda juga telah melewatkan kata kunci baru dalam jawaban dan terima kasih banyak atas sarannya :)
Ilya Chernomordik
10
@IlyaChernomordik ResponseMessagedan ResponseMessageResultdua hal berbeda. ResponseMessage()adalah metode dari ApiControlleryang kontroler Anda harus mewarisi dari, dan karena itu hanya panggilan metode. Jadi tidak ada newkata kunci yang diperlukan di sana. Anda mungkin tidak mewarisi dari ApiControlleratau Anda berada di dalam metode statis. ResponseMessageResultadalah tipe pengembalian ResponseMessage().
AaronLS
3
@IlyaChernomordik saya bisa menulis response = base.ResponseMessage(responseMsg)untuk membuatnya lebih jelas bahwa itu adalah metode yang ApiController kelas dasar
AaronLS
Terima kasih, saya memang memiliki layanan yang tidak mewarisi dari ApiController, itu sebabnya butuh beberapa waktu untuk menemukannya.
Ilya Chernomordik
3
@ bootzko Anda benar, saya membahas fakta bahwa OP tampaknya menyiratkan bahwa mereka percaya kedua pendekatan itu saling eksklusif dengan membingkainya sebagai "cara lama" vs "cara baru" padahal sebenarnya tidak. Saya pikir jawaban Darrel melakukan pekerjaan yang baik untuk menjelaskan beberapa manfaat dari mengembalikan IHttpActionResult, dan jawaban saya menunjukkan bagaimana Anda dapat mengubah HttpResponseMessage lama menjadi IHttpActionResult sehingga Anda dapat memiliki yang terbaik dari kedua dunia.
AaronLS
84

Anda masih bisa menggunakan HttpResponseMessage. Kemampuan itu tidak akan hilang. Saya merasakan hal yang sama seperti Anda dan berdebat secara luas dengan tim bahwa tidak ada kebutuhan untuk abstraksi tambahan. Ada beberapa argumen yang dilontarkan untuk mencoba dan membenarkan keberadaannya tetapi tidak ada yang meyakinkan saya bahwa itu berharga.

Begitulah, sampai saya melihat sampel ini dari Brad Wilson . Jika Anda membangun IHttpActionResultkelas dengan cara yang bisa dirantai, Anda memperoleh kemampuan untuk membuat pipa respons "tingkat tindakan" untuk menghasilkan HttpResponseMessage. Di bawah selimut, ini adalah bagaimana ActionFiltersdiimplementasikan Namun, pemesanan mereka ActionFilterstidak jelas ketika membaca metode tindakan yang merupakan salah satu alasan saya bukan penggemar filter tindakan.

Namun, dengan membuat sesuatu IHttpActionResultyang secara eksplisit dapat dirantai dalam metode tindakan Anda, Anda dapat menyusun semua jenis perilaku yang berbeda untuk menghasilkan respons Anda.

Darrel Miller
sumber
62

Berikut adalah beberapa manfaat dari IHttpActionResultlebih HttpResponseMessagedisebutkan dalam Dokumentasi Microsoft ASP.Net :

  • Unit yang disederhanakan menguji pengontrol Anda.
  • Memindahkan logika umum untuk membuat respons HTTP ke dalam kelas yang terpisah.
  • Menjadikan maksud tindakan pengontrol lebih jelas, dengan menyembunyikan detail tingkat rendah dari membangun respons.

Tetapi di sini ada beberapa keuntungan lain menggunakan IHttpActionResultlayak disebut:

  • Menghormati prinsip tanggung jawab tunggal : menyebabkan metode tindakan memiliki tanggung jawab melayani permintaan HTTP dan tidak melibatkan mereka dalam membuat pesan respons HTTP.
  • Implementasi yang berguna sudah didefinisikan dalam System.Web.Http.Hasil yaitu: Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState( tautan ke daftar lengkap )
  • Menggunakan Async dan Menunggu secara default.
  • Mudah membuat ActionResult sendiri hanya dengan menerapkan ExecuteAsyncmetode.
  • Anda dapat menggunakan ResponseMessageResult ResponseMessage(HttpResponseMessage response)untuk mengonversi HttpResponseMessage ke IHttpActionResult .
Behzad Bahmanyar
sumber
32
// this will return HttpResponseMessage as IHttpActionResult
return ResponseMessage(httpResponseMessage); 
Adam Tal
sumber
18

Ini hanya pendapat pribadi saya dan orang-orang dari tim API web mungkin dapat mengartikulasikannya dengan lebih baik tetapi ini adalah 2c saya.

Pertama-tama, saya pikir ini bukan pertanyaan satu sama lain. Anda dapat menggunakan keduanya tergantung pada apa yang ingin Anda lakukan dalam metode aksi Anda, tetapi untuk memahami kekuatan sesungguhnya dari IHttpActionResult, Anda mungkin akan perlu langkah di luar metode-metode penolong nyaman ApiControllerseperti Ok, NotFound, dll

Pada dasarnya, saya pikir kelas menerapkan IHttpActionResultsebagai pabrik HttpResponseMessage. Dengan pola pikir itu, sekarang menjadi objek yang perlu dikembalikan dan pabrik yang memproduksinya. Dalam pengertian pemrograman umum, Anda dapat membuat objek sendiri dalam kasus-kasus tertentu dan dalam kasus-kasus tertentu, Anda memerlukan pabrik untuk melakukan itu. Sama disini.

Jika Anda ingin mengembalikan respons yang perlu dibangun melalui logika yang kompleks, katakan banyak header respons, dll, Anda dapat mengabstraksi semua logika tersebut menjadi kelas hasil tindakan yang diterapkan IHttpActionResultdan menggunakannya dalam berbagai metode tindakan untuk mengembalikan respons.

Keuntungan lain menggunakan IHttpActionResultsebagai tipe pengembalian adalah membuat metode tindakan ASP.NET Web API mirip dengan MVC. Anda dapat mengembalikan hasil tindakan apa pun tanpa terjebak dalam pembuat format media.

Tentu saja, seperti dicatat oleh Darrel, Anda dapat mengaitkan hasil tindakan dan membuat pipa mikro yang kuat mirip dengan penangan pesan sendiri di pipa API. Ini akan Anda butuhkan tergantung pada kompleksitas metode tindakan Anda.

Singkat cerita - tidak IHttpActionResultberbanding terbalik HttpResponseMessage. Pada dasarnya, ini adalah bagaimana Anda ingin membuat respons. Lakukan sendiri atau melalui pabrik.

Badri
sumber
Masalah yang saya miliki dengan justfikasi pabrik adalah bahwa saya dapat dengan mudah membuat metode statis seperti ResponseFactory.CreateOkResponse()itu mengembalikan HttpResponseMessage, dan saya tidak harus berurusan dengan hal-hal async saat membuat respons. Satu anggota tim memang menyebutkan fakta bahwa async dapat berguna jika Anda perlu melakukan I / O untuk menghasilkan nilai header. Tidak yakin seberapa sering itu terjadi.
Darrel Miller
Saya pikir itu sama dengan mengatakan mengapa kita membutuhkan pola metode pabrik. Mengapa tidak menggunakan metode statis untuk membuat objek. Tentu, ini bisa dilakukan - setiap pembuatan objek tidak pantas dengan pola pabrik yang tepat. Tapi IMHO itu tergantung pada bagaimana Anda ingin memodelkan kelas Anda. Apakah Anda ingin memiliki logika untuk membuat berbagai jenis respons yang semuanya dijejalkan ke dalam kelas dalam bentuk beberapa metode statis atau memiliki kelas yang berbeda berdasarkan pada antarmuka. Sekali lagi, tidak ada yang baik atau buruk. Semuanya tergantung. Ngomong-ngomong, maksud saya adalah bahwa itu bukan salah satu dari yang lain dan saya pribadi lebih suka hal pabrik :)
Badri
6

Web API pada dasarnya kembali 4 jenis objek: void, HttpResponseMessage, IHttpActionResult, dan jenis kuat lainnya. Versi pertama dari API Web kembali HttpResponseMessageyang cukup lurus ke depan pesan respon HTTP.

Itu IHttpActionResultdiperkenalkan oleh WebAPI 2 yang merupakan semacam bungkus HttpResponseMessage. Ini berisi ExecuteAsync()metode untuk membuat HttpResponseMessage. Ini menyederhanakan pengujian unit controller Anda.

Jenis pengembalian lainnya adalah jenis kelas mengetik yang kuat yang diserialisasi oleh API Web menggunakan formatter media ke dalam badan respons. Kekurangannya adalah Anda tidak dapat langsung mengembalikan kode kesalahan seperti 404. Yang dapat Anda lakukan hanyalah melempar HttpResponseExceptionkesalahan.

Peter. Wang
sumber
3

Saya lebih suka mengimplementasikan fungsi antarmuka TaskExecuteAsync untuk IHttpActionResult. Sesuatu seperti:

    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);
    }

, di mana _request adalah HttpRequest dan _respContent adalah payload.

appletwo
sumber
2

Kami memiliki manfaat menggunakan IHttpActionResultlebih dari HttpResponseMessage:

  1. Dengan menggunakan IHttpActionResultkami hanya berkonsentrasi pada data yang akan dikirim bukan pada kode status. Jadi di sini kodenya akan lebih bersih dan sangat mudah dirawat.
  2. Pengujian unit dari metode pengontrol yang diterapkan akan lebih mudah.
  3. Penggunaan asyncdan awaitsecara default.
Debendra Dash
sumber