Tại sao tôi nên sử dụng IHttpActionResult thay vì HttpResponseMessage?


326

Tôi đã phát triển với WebApi và đã chuyển sang WebApi2 nơi Microsoft đã giới thiệu một IHttpActionResultGiao diện mới dường như được khuyến nghị sử dụng qua việc trả lại a HttpResponseMessage. Tôi bối rối về những lợi thế của Giao diện mới này. Dường như với chủ yếu chỉ cung cấp một chút cách dễ dàng hơn để tạo ra một HttpResponseMessage.

Tôi sẽ đưa ra lập luận rằng đây là "trừu tượng vì lợi ích trừu tượng". Tui bỏ lỡ điều gì vậy? Những lợi thế trong thế giới thực mà tôi có được từ việc sử dụng Giao diện mới này bên cạnh việc có thể lưu một dòng mã là gì?

Cách cũ (WebApi):

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

Cách mới (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();
    }
}

Tôi chỉ tìm thấy một cái gì đó thú vị. Tôi không chắc chắn nếu những kết quả này có thể được xác nhận bởi người khác. Nhưng hiệu suất đã cải thiện rất nhiều với một số cuộc gọi tôi đã thực hiện: * Với một ví dụ sử dụng HttpResponseMessagetôi đã nhận được phản hồi trong 9545 ms . * Sử dụng IHttpActionResultphản hồi tôi nhận được phản hồi tương tự trong 294 ms .
tổn thương chris

@chrislesage 9545 ms là gần 10 giây. Ngay cả 294ms là loại chậm. Nếu bạn có bất cứ điều gì mất hơn 100ms thì một cái gì đó khác đang hoạt động ở đó. Có nhiều câu chuyện hơn là gặp ete.
AaronLS

Câu trả lời:


305

Bạn có thể quyết định không sử dụng IHttpActionResultvì mã hiện tại của bạn xây dựng mã HttpResponseMessagekhông phù hợp với một trong các phản hồi đóng hộp. Tuy nhiên, bạn có thể thích nghi HttpResponseMessagevới IHttpActionResultviệc sử dụng phản ứng đóng hộp của ResponseMessage. Tôi phải mất một thời gian để tìm ra điều này, vì vậy tôi muốn đăng nó cho thấy rằng bạn không nhất thiết phải chọn cái này hay cái khác:

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

Lưu ý, ResponseMessagelà một phương thức của lớp cơ sở ApiControllermà bộ điều khiển của bạn nên kế thừa từ đó.


1
Mất một lúc tôi mới phát hiện ra rằng FeedbackMessage hiện đang là FeedbackMessageResult. Có lẽ nó đã được đổi tên gần đây? PS Bạn cũng đã bỏ lỡ một từ khóa mới trong câu trả lời và cảm ơn rất nhiều vì đã gợi ý :)
Ilya Chernomordik

10
@IlyaCécomordik ResponseMessageResponseMessageResultlà hai điều khác nhau. ResponseMessage()là một phương pháp của ApiControllermà điều khiển của bạn nên kế thừa từ, và do đó chỉ là một lời gọi phương thức. Vì vậy, không có newtừ khóa là cần thiết ở đó. Bạn có thể không kế thừa từ ApiControllerhoặc bạn đang ở trong một phương thức tĩnh. ResponseMessageResultlà loại trả về của ResponseMessage().
AaronLS 6/2/2015

3
@IlyaChernomordik tôi có thể viết response = base.ResponseMessage(responseMsg)để làm cho nó rõ ràng hơn rằng đó là một phương pháp của ApiController lớp cơ sở
AaronLS

Cảm ơn, tôi đã có một dịch vụ thực sự không được kế thừa từ ApiControll, đó là lý do tại sao phải mất một thời gian để tìm.
Ilya Chernomordik

3
@pootzko Bạn nói đúng, tôi đã đề cập đến thực tế là OP dường như ngụ ý rằng họ tin rằng hai cách tiếp cận loại trừ lẫn nhau bằng cách đóng khung nó là "cách cũ" và "cách mới" trong khi thực tế chúng không như vậy. Tôi nghĩ rằng câu trả lời của Darrel thực hiện tốt việc giải thích một số lợi ích của việc trả lại IHttpActionResult và câu trả lời của tôi cho thấy cách bạn có thể chuyển đổi httpResponseMessage cũ thành IHttpActionResult để bạn có thể có được cả hai thế giới tốt nhất.
AaronLS

84

Bạn vẫn có thể sử dụng HttpResponseMessage. Khả năng đó sẽ không biến mất. Tôi cũng cảm thấy giống như bạn và tranh luận rộng rãi với nhóm rằng không cần phải trừu tượng hóa thêm. Có một vài lập luận được đưa ra để thử và biện minh cho sự tồn tại của nó nhưng không có gì thuyết phục tôi rằng nó đáng giá.

Đó là, cho đến khi tôi nhìn thấy mẫu này từ Brad Wilson . Nếu bạn xây dựng IHttpActionResultcác lớp theo cách có thể được xâu chuỗi, bạn có khả năng tạo ra một đường ống phản ứng "mức độ hành động" để tạo ra HttpResponseMessage. Dưới vỏ bọc, đây là cách ActionFilterstriển khai, tuy nhiên, thứ tự của những thứ đó ActionFilterskhông rõ ràng khi đọc phương thức hành động, đó là một lý do tôi không phải là fan hâm mộ của các bộ lọc hành động.

Tuy nhiên, bằng cách tạo một IHttpActionResultchuỗi có thể được xâu chuỗi rõ ràng trong phương thức hành động của bạn, bạn có thể kết hợp tất cả các loại hành vi khác nhau để tạo phản hồi của mình.


62

Dưới đây là một số lợi ích của IHttpActionResulttrên HttpResponseMessageđề cập trong Microsoft ASP.Net Tài liệu :

  • Đơn giản hóa việc kiểm tra đơn vị bộ điều khiển của bạn.
  • Di chuyển logic chung để tạo phản hồi HTTP thành các lớp riêng biệt.
  • Làm cho ý định của bộ điều khiển hành động rõ ràng hơn, bằng cách ẩn các chi tiết cấp thấp của việc xây dựng phản hồi.

Nhưng đây là một số lợi thế khác của việc sử dụng IHttpActionResultđáng nói:

  • Tôn trọng nguyên tắc trách nhiệm duy nhất : khiến các phương thức hành động có trách nhiệm phục vụ các yêu cầu HTTP và không liên quan đến chúng trong việc tạo các thông điệp phản hồi HTTP.
  • Các triển khai hữu ích đã được xác định trong System.Web.Http.Results cụ thể là: Ok NotFound Exception Unauthorized BadRequest Conflict Redirect InvalidModelState( liên kết đến danh sách đầy đủ )
  • Sử dụng Async và Await theo mặc định.
  • Dễ dàng tạo ActionResult riêng chỉ bằng cách thực hiện ExecuteAsyncphương thức.
  • bạn có thể sử dụng ResponseMessageResult ResponseMessage(HttpResponseMessage response)để chuyển đổi httpResponseMessage sang IHttpActionResult .

32
// this will return HttpResponseMessage as IHttpActionResult
return ResponseMessage(httpResponseMessage); 

18

Đây chỉ là ý kiến ​​cá nhân của tôi và những người trong nhóm API web có thể nói rõ hơn nhưng đây là 2c của tôi.

Trước hết, tôi nghĩ đó không phải là câu hỏi của người khác. Bạn có thể sử dụng chúng cả tùy thuộc vào những gì bạn muốn làm trong phương pháp hành động của bạn, nhưng để hiểu được sức mạnh thực sự của IHttpActionResult, có thể bạn sẽ cần phải bước ra ngoài những phương pháp helper thuận tiện ApiControllernhư Ok, NotFoundvv

Về cơ bản, tôi nghĩ rằng một lớp thực hiện IHttpActionResultnhư là một nhà máy của HttpResponseMessage. Với ý nghĩ đó, giờ đây nó trở thành một đối tượng cần được trả lại và một nhà máy sản xuất ra nó. Theo nghĩa lập trình chung, bạn có thể tự tạo đối tượng trong một số trường hợp nhất định và trong một số trường hợp nhất định, bạn cần một nhà máy để làm điều đó. Tương tự ở đây.

Nếu bạn muốn trả về một phản hồi cần được xây dựng thông qua một logic phức tạp, giả sử có rất nhiều tiêu đề phản hồi, v.v., bạn có thể trừu tượng tất cả các logic đó thành một lớp kết quả hành động triển khai IHttpActionResultvà sử dụng nó trong nhiều phương thức hành động để trả về phản hồi.

Một ưu điểm khác của việc sử dụng IHttpActionResultnhư kiểu trả về là nó làm cho phương thức hành động ASP.NET Web API tương tự như MVC. Bạn có thể trả về bất kỳ kết quả hành động nào mà không bị bắt trong trình định dạng phương tiện truyền thông.

Tất nhiên, như Darrel lưu ý, bạn có thể xâu chuỗi các kết quả hành động và tạo ra một đường ống vi mô mạnh mẽ tương tự như trình xử lý tin nhắn trong đường ống API. Điều này bạn sẽ cần tùy thuộc vào độ phức tạp của phương thức hành động của bạn.

Câu chuyện dài - nó không IHttpActionResultso với HttpResponseMessage. Về cơ bản, đó là cách bạn muốn tạo phản hồi. Tự làm hoặc thông qua một nhà máy.


Vấn đề tôi gặp phải với sự minh chứng của nhà máy là tôi có thể dễ dàng tạo ra các phương thức tĩnh như ResponseFactory.CreateOkResponse()trả lại httpResponseMessage và tôi không phải xử lý các công cụ không đồng bộ khi tạo phản hồi. Một thành viên trong nhóm đã đề cập đến thực tế là async có thể hữu ích nếu bạn cần thực hiện I / O để tạo giá trị tiêu đề. Không chắc chắn mức độ thường xuyên xảy ra mặc dù.
Darrel Miller

Tôi nghĩ nó giống như nói tại sao chúng ta cần mô hình phương thức nhà máy. Tại sao không chỉ sử dụng các phương thức tĩnh để tạo đối tượng. Chắc chắn, điều đó là có thể thực hiện được - mọi sáng tạo đối tượng không xứng đáng với một mô hình nhà máy phù hợp. Nhưng sau đó IMHO nó phụ thuộc vào cách bạn muốn mô hình hóa các lớp học của bạn. Bạn có muốn có logic để tạo ra các loại phản hồi khác nhau được nhồi nhét vào một lớp dưới dạng nhiều phương thức tĩnh hoặc có các lớp khác nhau dựa trên một giao diện. Một lần nữa, không có tốt hay xấu. Tất cả phụ thuộc vào. Dù sao, quan điểm của tôi là nó không phải là cái khác và cá nhân tôi thích nhà máy hơn :)
Badri

6

API Web cơ bản trở 4 loại đối tượng: void, HttpResponseMessage, IHttpActionResult, và các loại mạnh khác. Phiên bản đầu tiên của API Web trả về HttpResponseMessagethông điệp phản hồi HTTP khá đơn giản.

Các IHttpActionResultđã được giới thiệu bởi WebAPI 2 mà là một loại bọc của HttpResponseMessage. Nó chứa ExecuteAsync()phương thức để tạo một HttpResponseMessage. Nó đơn giản hóa kiểm tra đơn vị của bộ điều khiển của bạn.

Kiểu trả về khác là loại lớp được gõ mạnh được API Web tuần tự hóa bằng cách sử dụng bộ định dạng phương tiện vào phần thân phản hồi. Hạn chế là bạn không thể trực tiếp trả về mã lỗi, chẳng hạn như 404. Tất cả những gì bạn có thể làm là ném HttpResponseExceptionlỗi.


3

Tôi muốn triển khai chức năng giao diện TaskExecuteAsync cho IHttpActionResult. Cái gì đó như:

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

, trong đó _request là httpRequest và _respContent là tải trọng.


2

Chúng tôi có những lợi ích sau khi sử dụng IHttpActionResulthơn HttpResponseMessage:

  1. Bằng cách sử dụng, IHttpActionResultchúng tôi chỉ tập trung vào dữ liệu được gửi chứ không phải mã trạng thái. Vì vậy, ở đây mã sẽ sạch hơn và rất dễ bảo trì.
  2. Kiểm tra đơn vị của phương pháp điều khiển thực hiện sẽ dễ dàng hơn.
  3. Sử dụng asyncawaittheo mặc định.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.