วิธีการคืน HTTP 500 จาก ASP.NET Core RC2 Web Api


189

ย้อนกลับไปใน RC1 ฉันจะทำสิ่งนี้:

[HttpPost]
public IActionResult Post([FromBody]string something)
{    
    try{
        // ...
    }
    catch(Exception e)
    {
         return new HttpStatusCodeResult((int)HttpStatusCode.InternalServerError);
    }
}

ใน RC2 ไม่มี HttpStatusCodeResult อีกต่อไปและไม่มีสิ่งใดที่ฉันสามารถค้นพบได้ซึ่งช่วยให้ฉันส่งคืน IActionResult ประเภท 500

ตอนนี้วิธีการนั้นแตกต่างกันอย่างสิ้นเชิงกับสิ่งที่ฉันถามหรือไม่? เราไม่ลองใช้Controllerโค้ดอีกต่อไปหรือไม่ เราเพียงแค่ปล่อยให้เฟรมเวิร์กส่งข้อยกเว้น 500 ทั่วไปกลับไปที่ผู้เรียก API หรือไม่ สำหรับการพัฒนาฉันจะดูสแต็กข้อยกเว้นที่แน่นอนได้อย่างไร

คำตอบ:


243

จากสิ่งที่ฉันเห็นมีวิธีช่วยเหลือภายในControllerBaseชั้นเรียน เพียงใช้StatusCodeวิธีการ:

[HttpPost]
public IActionResult Post([FromBody] string something)
{    
    //...
    try
    {
        DoSomething();
    }
    catch(Exception e)
    {
         LogException(e);
         return StatusCode(500);
    }
}

นอกจากนี้คุณยังสามารถใช้StatusCode(int statusCode, object value)โอเวอร์โหลดซึ่งยังเจรจาเนื้อหา


7
การทำเช่นนี้เราสูญเสียส่วนหัว CORS ดังนั้นข้อผิดพลาดจึงถูกซ่อนจากไคลเอนต์เบราว์เซอร์ V ทำลาย
bbsimonbb

2
@bbsimonbb ข้อผิดพลาดภายในควรถูกซ่อนจากลูกค้า พวกเขาควรถูกบันทึกไว้สำหรับนักพัฒนา
หิมาลัย Garg

10
นักพัฒนาควรมีความสุขแบบดั้งเดิมสิทธิพิเศษในการเลือกระดับของข้อมูลข้อผิดพลาดที่ส่งคืน
bbsimonbb

179

คุณสามารถใช้Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodeและMicrosoft.AspNetCore.Http.StatusCodesสร้างการตอบกลับของคุณหากคุณไม่ต้องการ hardcode หมายเลขเฉพาะ

return  StatusCode(StatusCodes.Status500InternalServerError);

อัพเดท: ส.ค. 2562

อาจไม่เกี่ยวข้องโดยตรงกับคำถามต้นฉบับ แต่เมื่อพยายามบรรลุผลลัพธ์เดียวกันกับMicrosoft Azure Functionsฉันพบว่าฉันต้องสร้างStatusCodeResultวัตถุใหม่ที่พบในการMicrosoft.AspNetCore.Mvc.Coreชุมนุม รหัสของฉันตอนนี้มีลักษณะเช่นนี้;

return new StatusCodeResult(StatusCodes.Status500InternalServerError);

11
ยอดเยี่ยมหนึ่งหลีกเลี่ยงส่วน hardcoded ใด ๆ / "หมายเลขเวทมนตร์" ฉันเคยใช้ StatusCode ((int) HttpStatusCode.InternalServerError) มาก่อน แต่ฉันชอบคุณมากกว่า
aleor

1
สิ่งหนึ่งที่ฉันไม่ได้พิจารณาในขณะนั้นคือทำให้โค้ดอ่านได้ง่ายขึ้นกลับมาที่คุณคุณรู้ว่าหมายเลขข้อผิดพลาด 500 เกี่ยวข้องกับอะไรมันอยู่ในโค้ด การจัดทำเอกสารด้วยตนเอง :-)
Edward Comeau

11
ฉันไม่สามารถจินตนาการข้อผิดพลาดเซิร์ฟเวอร์ภายใน (500) ที่เปลี่ยนแปลงได้ทุกเวลาเร็ว ๆ นี้
ม้วน

2
น่ากลัว สิ่งนี้ยังทำความสะอาดคุณสมบัติการวางท่าของฉันอย่างแท้จริง เช่น: [ProducesResponseType (StatusCodes.Status500InternalServerError)]
แดง 510

43

หากคุณต้องการร่างกายในการตอบสนองของคุณคุณสามารถโทร

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

สิ่งนี้จะคืนค่า 500 ด้วยวัตถุตอบกลับ ...


3
หากคุณไม่ต้องการสร้างประเภทออบเจกต์การตอบกลับที่เฉพาะเจาะจง: return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });และแน่นอนคุณสามารถเพิ่มข้อความอธิบายตามที่คุณต้องการและองค์ประกอบอื่น ๆ ได้เช่นกัน
Mike Taverne

18

วิธีที่ดีกว่าในการจัดการนี้ ณ ขณะนี้ (1.1) คือการทำเช่นนี้ในStartup.cs's Configure():

app.UseExceptionHandler("/Error");

/Errorซึ่งจะดำเนินการเส้นทาง การทำเช่นนี้จะช่วยคุณไม่ให้เพิ่มบล็อก try-catch ลงในทุกการกระทำที่คุณเขียน

แน่นอนคุณจะต้องเพิ่ม ErrorController แบบนี้:

[Route("[controller]")]
public class ErrorController : Controller
{
    [Route("")]
    [AllowAnonymous]
    public IActionResult Get()
    {
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
}

ข้อมูลเพิ่มเติมที่นี่


ในกรณีที่คุณต้องการได้รับข้อมูลข้อยกเว้นที่แท้จริงคุณสามารถเพิ่มสิ่งนี้ไปทางด้านGet()ขวาก่อนreturnคำสั่ง

// Get the details of the exception that occurred
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();

if (exceptionFeature != null)
{
    // Get which route the exception occurred at
    string routeWhereExceptionOccurred = exceptionFeature.Path;

    // Get the exception that occurred
    Exception exceptionThatOccurred = exceptionFeature.Error;

    // TODO: Do something with the exception
    // Log it with Serilog?
    // Send an e-mail, text, fax, or carrier pidgeon?  Maybe all of the above?
    // Whatever you do, be careful to catch any exceptions, otherwise you'll end up with a blank page and throwing a 500
}

ด้านบนข้อมูลโค้ดนำมาจากบล็อกของสกอตต์ของ Sauber


มันยอดเยี่ยม แต่ฉันจะบันทึกข้อยกเว้นที่ถูกโยนได้อย่างไร
redwards510

@ redwards510 นี่คือวิธีที่คุณทำ: scottsauber.com/2017/04/03/…ฉันจะอัปเดตคำตอบของฉันเพื่อสะท้อนให้เห็นเนื่องจากเป็นกรณีการใช้งานทั่วไปมาก😊
gldraphael

@gldraphael เรากำลังใช้งาน Core 2.1 อยู่ บล็อกของ Scott นั้นยอดเยี่ยม แต่ฉันอยากรู้ว่าถ้าใช้ IExceptionHandlerPathFeature เป็นแนวทางปฏิบัติที่ดีที่สุดในปัจจุบัน บางทีการสร้างมิดเดิลแวร์แบบกำหนดเองนั้นดีกว่าไหม
พาเวล

@Pavel เราใช้ExceptionHandlerมิดเดิลแวร์ที่นี่ แน่นอนคุณอาจม้วนตัวเองหรือยืดออกตามที่เห็นสมควร นี่คือเชื่อมโยงไปยังแหล่งที่มา แก้ไข: ดูบรรทัดนี้IExceptionHandlerPathFeature สำหรับ
gldraphael

15
return StatusCode((int)HttpStatusCode.InternalServerError, e);

ควรใช้ในบริบทที่ไม่ใช่ ASP.NET (ดูคำตอบอื่น ๆ สำหรับ ASP.NET Core)

HttpStatusCodeSystem.Netเป็นการแจงนับใน


12

วิธีการเกี่ยวกับการสร้างคลาส ObjectResult ที่กำหนดเองที่แสดงถึงข้อผิดพลาดเซิร์ฟเวอร์ภายในเช่นเดียวกับOkObjectResult? คุณสามารถใส่วิธีการที่ง่ายในระดับฐานของคุณเองเพื่อให้คุณสามารถสร้าง InternalServerError และส่งกลับมาเช่นเดียวกับคุณหรือOk()BadRequest()

[Route("api/[controller]")]
[ApiController]
public class MyController : MyControllerBase
{
    [HttpGet]
    [Route("{key}")]
    public IActionResult Get(int key)
    {
        try
        {
            //do something that fails
        }
        catch (Exception e)
        {
            LogException(e);
            return InternalServerError();
        }
    }
}

public class MyControllerBase : ControllerBase
{
    public InternalServerErrorObjectResult InternalServerError()
    {
        return new InternalServerErrorObjectResult();
    }

    public InternalServerErrorObjectResult InternalServerError(object value)
    {
        return new InternalServerErrorObjectResult(value);
    }
}

public class InternalServerErrorObjectResult : ObjectResult
{
    public InternalServerErrorObjectResult(object value) : base(value)
    {
        StatusCode = StatusCodes.Status500InternalServerError;
    }

    public InternalServerErrorObjectResult() : this(null)
    {
        StatusCode = StatusCodes.Status500InternalServerError;
    }
}

6

เมื่อคุณต้องการส่งคืนการตอบสนอง JSON ใน MVC .Net Core คุณยังสามารถใช้:

Response.StatusCode = (int)HttpStatusCode.InternalServerError;//Equals to HTTPResponse 500
return Json(new { responseText = "my error" });

สิ่งนี้จะส่งคืนทั้งผลลัพธ์ JSON และ HTTPStatus ฉันใช้เพื่อคืนผลลัพธ์ให้ jQuery.ajax ()


1
ฉันต้องใช้return new JsonResult ...แต่ก็ใช้งานได้ดีมาก
Mike Taverne

5

สำหรับ aspnetcore-3.1 คุณสามารถใช้Problem()ดังนี้

https://docs.microsoft.com/en-us/aspnet/core/web-api/handle-errors?view=aspnetcore-3.1

 [Route("/error-local-development")]
public IActionResult ErrorLocalDevelopment(
    [FromServices] IWebHostEnvironment webHostEnvironment)
{
    if (webHostEnvironment.EnvironmentName != "Development")
    {
        throw new InvalidOperationException(
            "This shouldn't be invoked in non-development environments.");
    }

    var context = HttpContext.Features.Get<IExceptionHandlerFeature>();

    return Problem(
        detail: context.Error.StackTrace,
        title: context.Error.Message);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.