เหตุใดฉันจึงควรใช้ IHttpActionResult แทน HttpResponseMessage


326

ฉันได้รับการพัฒนากับ WebAPI และได้ย้ายไป WebApi2 ที่ไมโครซอฟท์ได้แนะนำใหม่อินเตอร์เฟซที่ดูเหมือนว่าจะแนะนำให้นำมาใช้มากกว่ากลับ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 มิลลิวินาที * ใช้IHttpActionResultผมได้กลับมาตอบสนองเดียวกันใน294 มิลลิวินาที
chris lesage

@chrislesage 9545 ms เกือบ 10 วินาที แม้แต่ 294 มิลลิวินาทีก็ช้า หากคุณมีสิ่งใดที่ใช้เวลามากกว่า 100ms แสดงว่ามีอย่างอื่นอยู่ที่นั่น เรื่องราวมีมากกว่านั้นตรงกับเอเต้
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 นอกจากนี้คุณยังไม่ได้รับคำหลักใหม่ในคำตอบและขอบคุณมากสำหรับคำแนะนำ :)
Ilya Chernomordik

10
@ IlyaChernomordik ResponseMessageและResponseMessageResultเป็นสองสิ่งที่แตกต่างกัน ResponseMessage()เป็นวิธีการของApiControllerตัวควบคุมของคุณควรได้รับมรดกจากและดังนั้นจึงเป็นเพียงการเรียกวิธี ดังนั้นไม่newจำเป็นต้องมีคำหลัก คุณอาจไม่ได้รับมรดกApiControllerหรือคุณอยู่ในวิธีการคงที่ เป็นชนิดที่การกลับมาของResponseMessageResult ResponseMessage()
AaronLS

3
@IlyaChernomordik ฉันสามารถเขียนresponse = base.ResponseMessage(responseMsg)เพื่อให้ชัดเจนยิ่งขึ้นว่าเป็นวิธีการของ ApiController ระดับฐาน
AaronLS

ขอบคุณฉันมีบริการที่ไม่ได้สืบทอดมาจาก ApiController นั่นเป็นเหตุผลว่าทำไมจึงต้องใช้เวลาพอสมควรในการค้นหา
Ilya Chernomordik

3
@pootzko ถูกต้องฉันพูดถึงความจริงที่ว่า OP ดูเหมือนจะบอกเป็นนัยว่าพวกเขาเชื่อว่าทั้งสองวิธีนั้นไม่เหมือนกันโดยกำหนดกรอบเป็น "วิธีเก่า" กับ "วิธีใหม่" ในความเป็นจริง ฉันคิดว่าคำตอบของ Darrel ทำงานได้ดีในการอธิบายถึงประโยชน์ของการคืน 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 ของฉันสามารถพูดได้ดีขึ้น แต่นี่คือ 2c ของฉัน

ก่อนอื่นฉันคิดว่ามันไม่ใช่คำถามของอีกคน คุณสามารถใช้พวกเขาทั้งสองขึ้นอยู่กับสิ่งที่คุณต้องการจะทำในวิธีการของการกระทำของคุณ แต่เพื่อให้เข้าใจในพลังที่แท้จริงของIHttpActionResultคุณอาจจะต้องขั้นตอนที่ผู้ที่อยู่นอกวิธีการช่วยเหลือสะดวกApiControllerเช่นOk, NotFoundฯลฯ

โดยทั่วไปผมคิดว่าการดำเนินการในชั้นเรียนเป็นโรงงานของIHttpActionResult HttpResponseMessageด้วยชุดความคิดนั้นตอนนี้มันจะกลายเป็นวัตถุที่ต้องส่งคืนและโรงงานที่ผลิตมัน โดยทั่วไปการเขียนโปรแกรมคุณสามารถสร้างวัตถุด้วยตัวเองในบางกรณีและในบางกรณีคุณต้องมีโรงงานเพื่อทำเช่นนั้น กันที่นี่

หากคุณต้องการส่งคืนการตอบกลับที่จำเป็นต้องสร้างผ่านตรรกะที่ซับซ้อนให้พูดส่วนหัวการตอบกลับจำนวนมากและอื่น ๆ คุณสามารถสรุปตรรกะทั้งหมดเหล่านั้นลงในคลาสผลการดำเนินการIHttpActionResultและนำไปใช้ในหลายวิธี

ข้อดีอีกอย่างของการใช้IHttpActionResultเป็นชนิดส่งคืนคือมันทำให้วิธีการดำเนินการ ASP.NET Web API คล้ายกับ MVC คุณสามารถส่งคืนผลลัพธ์การดำเนินการใด ๆ โดยไม่ติดอยู่ในตัวจัดรูปแบบสื่อ

แน่นอนตามที่ระบุไว้โดย Darrel คุณสามารถโยงผลลัพธ์การดำเนินการและสร้างไมโครไพน์ไลน์อันทรงพลังซึ่งคล้ายกับตัวจัดการข้อความใน API ไปป์ไลน์ สิ่งนี้คุณจะต้องใช้ขึ้นอยู่กับความซับซ้อนของวิธีการกระทำของคุณ

เรื่องยาวสั้น - มันไม่ได้เมื่อเทียบกับIHttpActionResult HttpResponseMessageโดยทั่วไปเป็นวิธีที่คุณต้องการสร้างการตอบสนอง ทำเองหรือผ่านโรงงาน


ปัญหาที่ฉันพบกับโรงงาน justfication คือฉันสามารถสร้างวิธีการแบบคงที่ได้อย่างง่ายดายเช่นResponseFactory.CreateOkResponse()HttpResponseMessage ที่ส่งคืนและฉันไม่ต้องจัดการกับ async stuff เมื่อสร้างการตอบสนอง สมาชิกในทีมคนหนึ่งพูดถึงความจริงที่ว่า async จะมีประโยชน์หากคุณต้องทำ I / O เพื่อสร้างค่าส่วนหัว ไม่แน่ใจว่าเกิดขึ้นบ่อยแค่ไหน
Darrel Miller

ฉันคิดว่ามันเหมือนกับพูดว่าทำไมเราถึงต้องใช้รูปแบบวิธีการจากโรงงาน ทำไมไม่เพียงแค่ใช้วิธีการคงที่เพื่อสร้างวัตถุ แน่นอนว่าเป็นไปได้ - การสร้างวัตถุทุกชิ้นไม่มีรูปแบบที่เหมาะสมจากโรงงาน แต่แล้ว IMHO ก็ขึ้นอยู่กับว่าคุณต้องการสร้างแบบจำลองชั้นเรียนของคุณอย่างไร คุณต้องการที่จะมีเหตุผลในการสร้างการตอบสนองที่แตกต่างกันทั้งหมดที่อัดแน่นเข้าไปในชั้นเรียนในรูปแบบของวิธีการคงที่หลายหรือมีชั้นเรียนที่แตกต่างกันขึ้นอยู่กับอินเตอร์เฟซ อีกครั้งไม่มีดีหรือไม่ดี ทุกอย่างขึ้นอยู่กับ Anyways, จุดของฉันก็คือว่ามันไม่ได้เป็นหนึ่งมากกว่าอีกและผมเองชอบสิ่งที่โรงงานดีกว่า :)
Badri

6

เว็บ 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ค่าเริ่มต้น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.