ส่งคืนเนื้อหาด้วย IHttpActionResult สำหรับการตอบกลับที่ไม่ตกลง


185

สำหรับการกลับมาจากคอนโทรลเลอร์ Web API 2 ฉันสามารถส่งคืนเนื้อหาพร้อมการตอบกลับหากการตอบสนองตกลง (สถานะ 200) ดังนี้:

    public IHttpActionResult Get()
    {
        string myResult = ...
        return Ok(myResult);
    }

หากเป็นไปได้ฉันต้องการใช้ประเภทผลลัพธ์ที่มีอยู่ภายในที่นี่เมื่อเป็นไปได้: https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

คำถามของฉันคือสำหรับการตอบกลับประเภทอื่น (ไม่ใช่ 200) ฉันจะส่งคืนข้อความ (สตริง) ด้วยได้อย่างไร ตัวอย่างเช่นฉันสามารถทำสิ่งนี้:

    public IHttpActionResult Get()
    {
       return InternalServerError();
    }

แต่ไม่ใช่:

    public IHttpActionResult Get()
    {
       return InternalServerError("Message describing the error here");
    }

เป็นการดีที่ฉันต้องการให้เป็นแบบทั่วไปเพื่อให้ฉันสามารถส่งข้อความกลับด้วยการใช้งานใด ๆ ของ IHttpActionResult

ฉันต้องทำสิ่งนี้หรือไม่ (และสร้างข้อความตอบกลับของตัวเอง):

    public IHttpActionResult Get()
    {
       HttpResponseMessage responseMessage = ...
       return ResponseMessage(responseMessage);
    }

หรือมีวิธีที่ดีกว่า


วิธีการเกี่ยวกับสิ่งนี้: stackoverflow.com/questions/10732644/…
Milen

คุณไม่สามารถใช้ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx ได้
Ric

@Milen ขอบคุณ บางสิ่งเช่นนี้อาจใช้ได้ผล ส่วนที่ฉันไม่ชอบคือมันต้องสร้างการปรับใช้ IHttpActionResult ที่แตกต่างกันสำหรับการใช้งานที่มีอยู่แต่ละครั้งที่ฉันต้องการใช้งาน
mayabelle

@Ric ไม่พารามิเตอร์มีข้อยกเว้น ฉันต้องการตั้งค่าข้อความเป็นสตริง นอกจากนี้ยังไม่ได้ระบุกรณีทั่วไปที่รหัสอาจไม่จำเป็นต้องเป็นเซิร์ฟเวอร์ภายใน
mayabelle

3
@mayabelle: คุณเห็นคำตอบของ Shamil Yakupov แล้วหรือยัง? มันง่ายและกระชับมากที่คำตอบที่ยอมรับ
Isaac

คำตอบ:


420

คุณสามารถใช้สิ่งนี้:

return Content(HttpStatusCode.BadRequest, "Any object");

1
วิธีแก้ปัญหาสั้นและง่าย การมีรหัสเพิ่มเติมหมายถึงข้อผิดพลาดและการบำรุงรักษาที่ใช้เวลานาน
Thomas.Benz

6
เมื่อฉันลองทำสิ่งนี้ค่าที่ส่งคืนของcode(โดยที่โค้ดคือสตริง) ในreturn Content(HttpStatusCode.OK, code)ถูกห่อหุ้มด้วย "ซึ่งไม่คาดคิดมีเหตุผลอะไรเช่นนี้หรือไม่เช่นค่าที่ส่งคืนคือ"\"value\""ฉันกำลังใช้ mvc5
Deza

2
ถ้าคุณต้องการทำสิ่งนี้จากนอกคลาส ApiController คุณสามารถใช้: คืนค่า NegotiatedContentResult <T> ใหม่ (โค้ด, T ใหม่ (... ), คอนโทรลเลอร์)
Etherman

ฉันจะส่งคืนจากไลบรารีคลาสหรือไม่? ฉันต้องการอ้างอิงอะไร
ชุดเครื่องมือ

54

คุณสามารถใช้HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.Httpnamespace) เช่น:

public IHttpActionResult Get()
{
   return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Message describing the error here"));
}

คุณควรสร้างการตอบกลับตามคำขอเพื่อใช้ประโยชน์จากการเจรจาต่อรองเนื้อหาของ Web API


6
Request.CreateErrorResponse ส่งคืน HttpResponseMessage ไม่ใช่ IHttpActionResult สิ่งที่คุณอธิบายคือแนวทางปฏิบัติที่ดีสำหรับการสร้าง HttpResponseMessage แต่ไม่ได้ตอบคำถามของฉัน ขอขอบคุณ!
mayabelle

@mayabelle คุณสามารถสร้าง IHttpActionResult คอนกรีตและห่อรหัสเหล่านี้ดังนี้:
Quoc Nguyen

1
สิ่งนี้ใช้ได้สำหรับฉัน แต่ฉันใช้ Request.CreateResponse เพื่อให้ข้อผิดพลาดแสดงเป็นสตริงแทนที่จะอยู่ภายใต้คีย์ข้อความ
นักเคมี

ฉันได้รับข้อผิดพลาดข้อมูลโค้ดล้มเหลว มันบอกว่า 'คำขอ' เป็นโมฆะ ฉันกำลังพยายามใช้ Request.CreateResponse @ user1620220
Sheena Agrawal

@SheenaAgrawal รหัสนี้สามารถเรียกใช้งานได้ในบริบทของคำขอ HTTP เท่านั้น ถ้าApiController.Requestเป็นโมฆะก็หมายความว่าคุณไม่ได้อยู่ในบริบทที่ถูกต้องหรือมีบางอย่างผิดปกติในสถาปัตยกรรม WebAPI ของคุณ
user1620220

35

ฉันลงเอยด้วยวิธีแก้ปัญหาต่อไปนี้:

public class HttpActionResult : IHttpActionResult
{
    private readonly string _message;
    private readonly HttpStatusCode _statusCode;

    public HttpActionResult(HttpStatusCode statusCode, string message)
    {
        _statusCode = statusCode;
        _message = message;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response = new HttpResponseMessage(_statusCode)
        {
            Content = new StringContent(_message)
        };
        return Task.FromResult(response);
    }
}

... ซึ่งสามารถใช้ดังนี้:

public IHttpActionResult Get()
{
   return new HttpActionResult(HttpStatusCode.InternalServerError, "error message"); // can use any HTTP status code
}

ฉันเปิดรับข้อเสนอแนะสำหรับการปรับปรุง :)


1
คำตอบของ Shamil Yakupov เป็นคำตอบที่ดีที่สุด แต่จากภายในคลาส ApiController เท่านั้น - จะต้องมีการเขียนใหม่เหมือน "ส่งคืน NegotiatedContentResult <T> ใหม่ (รหัส T ใหม่ (... ), ตัวควบคุม)" จากภายนอก คลาสคอนโทรลเลอร์ ในกรณีนั้นวิธีแก้ปัญหาเช่นนี้อาจจะอ่านง่ายขึ้น
Etherman

16

คุณยังสามารถทำสิ่งต่อไปนี้

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));

1
ใช่ แต่มันเป็นความเจ็บปวดที่จะได้รับข้อความนั้นกลับมา
userSteve

7

ทุกคนที่สนใจที่จะคืนสิ่งใด ๆ ด้วยรหัสสถานะใด ๆ ที่มีการตอบกลับ ResponseMessage:

//CreateResponse(HttpStatusCode, T value)
return ResponseMessage(Request.CreateResponse(HttpStatusCode.XX, object));

7

ใน ASP.NET Web API 2 คุณสามารถตัดคำใด ๆResponseMessageในResponseMessageResult :

public IHttpActionResult Get()
{
   HttpResponseMessage responseMessage = ...
   return new ResponseMessageResult(responseMessage);
}

ในบางกรณีนี้อาจเป็นวิธีที่ง่ายที่สุดที่จะได้รับผลที่ต้องการแม้ว่าโดยทั่วไปมันอาจจะดีกว่าที่จะใช้ผลต่าง ๆ ในSystem.Web.Http.Results


6

ง่าย:

return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Your message"));

อย่าลืมอ้างอิงSystem.Net.HttpและSystem.Net


2

ฉันอยากจะแนะนำให้อ่านโพสต์นี้ มีหลายวิธีในการใช้ HttpResponse ที่มีอยู่ตามที่แนะนำ แต่ถ้าคุณต้องการใช้ประโยชน์จาก Web Api 2 ให้ดูที่การใช้ตัวเลือก IHttpActionResult ในตัวเช่น

return Ok() 

หรือ

return NotFound()

เลือกประเภทผลตอบแทนที่เหมาะสมสำหรับ Web Api Controllers


2

ตัวอย่างที่มีรายละเอียดมากขึ้นด้วยการสนับสนุนของรหัส HTTP ไม่ได้กำหนดไว้ใน C HttpStatusCode#

public class MyController : ApiController
{
    public IHttpActionResult Get()
    {
        HttpStatusCode codeNotDefined = (HttpStatusCode)429;
        return Content(codeNotDefined, "message to be sent in response body");
    }
}

Contentเป็นวิธีเสมือนที่กำหนดไว้ในคลาสนามธรรมApiControllerฐานของตัวควบคุม ดูคำประกาศดังต่อไปนี้:

protected internal virtual NegotiatedContentResult<T> Content<T>(HttpStatusCode statusCode, T value);

1

@mayabelle คุณสามารถสร้าง IHttpActionResult คอนกรีตและห่อรหัสเหล่านี้ดังนี้

public class NotFoundPlainTextActionResult : IHttpActionResult
{
    public NotFoundPlainTextActionResult(HttpRequestMessage request, string message)
    {
        Request = request;
        Message = message;
    }

    public string Message { get; private set; }
    public HttpRequestMessage Request { get; private set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(ExecuteResult());
    }

    public HttpResponseMessage ExecuteResult()
    {
        var response = new HttpResponseMessage();

        if (!string.IsNullOrWhiteSpace(Message))
            //response.Content = new StringContent(Message);
            response = Request.CreateErrorResponse(HttpStatusCode.NotFound, new Exception(Message));

        response.RequestMessage = Request;
        return response;
    }
}

0

ผมมีปัญหาเหมือนกัน. ฉันต้องการสร้างผลลัพธ์ที่กำหนดเองสำหรับตัวควบคุม api ของฉันเพื่อเรียกพวกเขาเช่น return Ok("some text");

จากนั้นฉันก็ทำสิ่งนี้: 1) สร้างประเภทผลลัพธ์ที่กำหนดเองด้วย singletone

public sealed class EmptyResult : IHttpActionResult
{
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.NoContent) { Content = new StringContent("Empty result") });
    }
}

2) สร้างคอนโทรลเลอร์ที่กำหนดเองด้วยวิธีการใหม่:

public class CustomApiController : ApiController
{
    public IHttpActionResult EmptyResult()
    {
        return new EmptyResult();
    }
}

แล้วฉันจะเรียกมันว่าในตัวควบคุมของฉันแบบนี้:

public IHttpActionResult SomeMethod()
    {
       return EmptyResult();
    }

0

คำตอบนี้ขึ้นอยู่กับคำตอบของ Shamil Yakupov ด้วยวัตถุจริงแทนที่จะเป็นสตริง

using System.Dynamic;

dynamic response = new ExpandoObject();
response.message = "Email address already exist";

return Content<object>(HttpStatusCode.BadRequest, response);

1
เนื้อหา <T> มีประโยชน์มาก
LastTribunal

0

สำหรับข้อยกเว้นฉันมักจะทำ

 catch (Exception ex)
        {
            return InternalServerError(new ApplicationException("Something went wrong in this request. internal exception: " + ex.Message));
        }

0

เหนือสิ่งต่าง ๆ มีประโยชน์จริง ๆ

ในขณะที่การสร้างบริการเว็บถ้าคุณจะใช้กรณีของการบริการผู้บริโภคจะชื่นชมอย่างมาก ฉันพยายามที่จะรักษาความสม่ำเสมอของการส่งออก นอกจากนี้คุณสามารถให้ข้อสังเกตหรือข้อผิดพลาดที่เกิดขึ้นจริง ผู้ใช้บริการทางเว็บสามารถตรวจสอบได้เฉพาะ IsSuccess จริงหรือไม่จะแน่ใจได้ว่ามีปัญหาและทำตามสถานการณ์

  public class Response
    {
        /// <summary>
        /// Gets or sets a value indicating whether this instance is success.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is success; otherwise, <c>false</c>.
        /// </value>
        public bool IsSuccess { get; set; } = false;

        /// <summary>
        /// Actual response if succeed 
        /// </summary>
        /// <value>
        /// Actual response if succeed 
        /// </value>
        public object Data { get; set; } = null;

        /// <summary>
        /// Remark if anythig to convey
        /// </summary>
        /// <value>
        /// Remark if anythig to convey
        /// </value>
        public string Remark { get; set; } = string.Empty;
        /// <summary>
        /// Gets or sets the error message.
        /// </summary>
        /// <value>
        /// The error message.
        /// </value>
        public object ErrorMessage { get; set; } = null;


    }  




[HttpGet]
        public IHttpActionResult Employees()
        {
            Response _res = new Response();
            try
            { 
                DalTest objDal = new DalTest(); 
                _res.Data = objDal.GetTestData();
                _res.IsSuccess = true;
                return Ok<Response>(_res);
            }
            catch (Exception ex)
            {
                _res.IsSuccess = false;
                _res.ErrorMessage = ex;
                return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, _res )); 
            } 
        }

คุณสามารถให้ข้อเสนอแนะหากมี :)


-1

ขออภัยสำหรับคำตอบที่ล่าช้าทำไมคุณไม่ใช้ง่าย

return BadRequest("your message");

ฉันใช้มันสำหรับIHttpActionResultข้อผิดพลาดทั้งหมดของฉันมันทำงานได้ดี

นี่คือเอกสาร: https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx


7
เพราะไม่ใช่ข้อผิดพลาดทั้งหมดเป็นผลมาจากการร้องขอที่ไม่ดีดังนั้นการ400ตอบสนองจะไม่เหมาะสม OP ให้การ500ตอบสนองเป็นตัวอย่างโดยเฉพาะ
user1620220

ใช่เป็นไปได้เฉพาะกับ BadRequest เท่านั้นประเภทอื่น ๆ จะไม่โต้แย้งข้อความ
benraay
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.