Làm cách nào để trả về HTTP 500 từ Api ASP.NET Core RC2?


189

Quay trở lại RC1, tôi sẽ làm điều này:

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

Trong RC2, không còn là httpStatusCodeResult nữa và tôi không thể tìm thấy điều gì cho phép tôi trả về 500 loại IActionResult.

Cách tiếp cận bây giờ hoàn toàn khác với những gì tôi đang hỏi? Chúng ta không còn thử bắt trong Controllermã? Có phải chúng ta chỉ để khung công tác ném một ngoại lệ 500 chung cho người gọi API không? Để phát triển, làm thế nào tôi có thể thấy ngăn xếp ngoại lệ chính xác?

Câu trả lời:


242

Từ những gì tôi có thể thấy có các phương thức trợ giúp bên trong ControllerBaselớp. Chỉ cần sử dụng StatusCodephương pháp:

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

Bạn cũng có thể sử dụng StatusCode(int statusCode, object value)quá tải cũng thương lượng nội dung.


7
làm điều này, chúng tôi mất các tiêu đề CORS, do đó các lỗi được ẩn khỏi trình duyệt của khách hàng. V bực bội.
bbsimonbb

2
@bbsimonbb Lỗi nội bộ nên được ẩn khỏi máy khách. Họ nên được đăng nhập cho các nhà phát triển.
Himalaya Garg

10
Các nhà phát triển nên có, theo truyền thống được hưởng, đặc quyền để chọn mức thông tin lỗi được trả về.
bbsimonbb

179

Bạn có thể sử dụng Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodeMicrosoft.AspNetCore.Http.StatusCodeshình thành phản hồi của mình, nếu bạn không muốn mã hóa số cụ thể.

return  StatusCode(StatusCodes.Status500InternalServerError);

CẬP NHẬT: Tháng 8 năm 2019

Có lẽ không liên quan trực tiếp đến câu hỏi ban đầu nhưng khi cố gắng đạt được kết quả tương tự với Microsoft Azure Functionstôi thấy rằng tôi phải xây dựng một StatusCodeResultđối tượng mới được tìm thấy trong Microsoft.AspNetCore.Mvc.Corehội đồng. Mã của tôi bây giờ trông như thế này;

return new StatusCodeResult(StatusCodes.Status500InternalServerError);

11
Tuyệt vời, tránh bất kỳ phần mã hóa cứng / "số ma thuật". Tôi đã sử dụng StatusCode ((int) HttpStatusCode.IternalServerError) trước đây nhưng tôi thích bạn hơn.
aleor

1
Một điều tôi không xem xét tại thời điểm đó là nó làm cho mã dễ đọc hơn, quay trở lại với nó bạn biết lỗi số 500 liên quan đến điều gì, nó có ngay trong mã. Tự viết tài liệu :-)
Edward Comeau

11
Tôi không thể tưởng tượng lỗi máy chủ nội bộ (500) thay đổi bất cứ lúc nào sớm.
cuộn

2
tuyệt vời. điều này cũng thực sự làm sạch các thuộc tính vênh vang của tôi. ví dụ: [ProducesResponseType (StatusCodes.Status500I InternalalServerError)]
ProducesResponseType

43

Nếu bạn cần một cơ thể trong phản ứng của bạn, bạn có thể gọi

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

Điều này sẽ trả về 500 với đối tượng phản hồi ...


3
Nếu bạn không muốn tạo một loại đối tượng phản hồi cụ thể: return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });Và tất nhiên, bạn có thể thêm một thông điệp mô tả như bạn muốn và các yếu tố khác.
Mike Cheesne

18

Một cách tốt hơn để xử lý việc này tính đến nay (1.1) là để làm điều này trong Startup.cs's Configure():

app.UseExceptionHandler("/Error");

Điều này sẽ thực hiện tuyến đường cho /Error . Điều này sẽ giúp bạn tiết kiệm từ việc thêm các khối thử bắt vào mọi hành động bạn viết.

Tất nhiên, bạn sẽ cần thêm ErrorContoder tương tự như sau:

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

Thêm thông tin ở đây .


Trong trường hợp bạn muốn lấy dữ liệu ngoại lệ thực tế, bạn có thể thêm dữ liệu này vào bên trên Get()ngay trước returncâu lệnh.

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

Đoạn trích trên lấy từ blog của Scott Sauber .


Điều này thật tuyệt vời, nhưng làm thế nào tôi có thể ghi lại ngoại lệ đã bị ném?
redwards510

@ redwards510 Đây là cách bạn làm điều đó: scottsauber.com/2017/04/03/... tôi sẽ cập nhật câu trả lời của tôi để phản ánh nó, vì nó là một trường hợp sử dụng rất phổ biến 😊
gldraphael

@gldraphael Chúng tôi hiện đang sử dụng Core 2.1. Blog của Scott rất tuyệt, nhưng tôi tò mò nếu sử dụng IExceptionHandlerPathFeature hiện là cách thực hành tốt nhất được đề xuất. Có lẽ tạo phần mềm trung gian tùy chỉnh là tốt hơn?
Pavel

@Pavel chúng tôi đang sử dụng ExceptionHandlerphần mềm trung gian ở đây. Tất nhiên, bạn có thể tự cuộn hoặc mở rộng nó khi bạn thấy phù hợp. Đây là liên kết đến các nguồn . EDIT: Xem dòng này cho IExceptionHandlerPathFeature .
gldraphael

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

Nên được sử dụng trong bối cảnh non-ASP.NET (xem các câu trả lời khác cho ASP.NET Core).

HttpStatusCodelà một liệt kê trong System.Net.


11

Làm thế nào về việc tạo một lớp ObjectResult tùy chỉnh đại diện cho Lỗi Máy chủ Nội bộ giống như lỗi đối với OkObjectResult? Bạn có thể đặt một phương thức đơn giản trong lớp cơ sở của riêng bạn để bạn có thể dễ dàng tạo InternalServerError và trả về nó giống như bạn làm Ok()hoặc 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

Khi bạn muốn trả về phản hồi JSON trong MVC .Net Core Bạn cũng có thể sử dụng:

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

Điều này sẽ trả về cả kết quả JSON và HTTPStatus. Tôi sử dụng nó để trả về kết quả cho jQuery.ajax ().


1
Tôi đã phải sử dụng return new JsonResult ...nhưng nếu không làm việc tuyệt vời.
Mike Cheesne

5

Đối với aspnetcore-3.1, bạn cũng có thể sử dụng Problem()như dưới đây;

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