Як повернути 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, і я нічого не можу знайти, що дозволяє мені повернути 500 тип IActionResult.

Чи підхід зараз зовсім інший для того, про що я прошу? Ми більше не пробуємо в Controllerкоді? Чи просто ми дозволимо рамці відкинути загальний виняток 500 назад на абонент API? Як я можу побачити точний стек винятків для розвитку?

Відповіді:


241

Як я бачу, є допоміжні методи всередині 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 Внутрішні помилки слід приховувати від клієнтів. Вони повинні бути зареєстровані для розробників.
— Гімалая Гарг

10
Розробники повинні мати традиційне задоволення від вибору рівня повернення інформації про помилки.
— bbsimonbb

179

Ви можете використовувати Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodeта Microsoft.AspNetCore.Http.StatusCodesформувати свою відповідь, якщо не хочете вводити конкретні номери.

return  StatusCode(StatusCodes.Status500InternalServerError);

ОНОВЛЕННЯ: серпня 2019 року

Можливо, не пов’язане безпосередньо з початковим питанням, але, намагаючись досягти такого ж результату, Microsoft Azure Functionsя виявив, що мені довелося побудувати новий StatusCodeResultоб'єкт, знайдений у складі Microsoft.AspNetCore.Mvc.Core. Зараз мій код виглядає приблизно так;

return new StatusCodeResult(StatusCodes.Status500InternalServerError);

11
Чудова, уникає будь-яких твердо кодованих деталей / "магічних чисел". Я раніше використовував StatusCode ((int) HttpStatusCode.InternalServerError), але мені більше подобається ваш.
— алеор

1
Одне, що я не враховував на той час, це те, що він робить код більш читабельним, повертаючись до нього, ви знаєте, до якої помилки відноситься число 500, саме там у коді. Самодокументування :-)
— Едвард Комо

11
Я не можу уявити, що внутрішня помилка сервера (500) змінюється незабаром.
— булочки

2
приголомшливий це також дійсно очищає мої атрибути хитрості. Наприклад: [ProducesResponseType (StatusCodes.Status500InternalServerError)]
— redwards510

43

Якщо у відповіді вам потрібне тіло, ви можете зателефонувати

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

Це поверне 500 з об'єктом відповіді ...


3
Якщо ви не хочете створювати певний тип об'єкта відповіді: return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });І звичайно, ви можете додавати як описове повідомлення як завгодно, а також інші елементи.
— Майк

18

Кращий спосіб справитися з цим , як зараз (1.1) , щоб зробити це в Startup.cs«s Configure():

app.UseExceptionHandler("/Error");

Це виконає маршрут для /Error. Це вбереже вас від додавання пробних блоків до кожної дії, яку ви пишете.

Звичайно, вам потрібно буде додати 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
}

Вище фрагмент, зроблений із блогу Скотта Соубера .


це дивовижно, але як я можу зареєструвати виняток, який було кинуто?
— redwards510

@ redwards510 Ось як це зробити: scottsauber.com/2017/04/03/… Я оновлю свою відповідь, щоб відобразити її, оскільки це дуже поширений випадок використання use
— gldraphael

@gldraphael На даний момент ми використовуємо Core 2.1. Блог Скотта чудовий, але мені цікаво, якщо використання IExceptionHandlerPathFeature є рекомендованою найкращою практикою. Можливо, краще створити власні проміжні програми?
— Павло

@Pavel ми тут використовуємо ExceptionHandlerпроміжне програмне забезпечення. Ви, звичайно, можете закатати свою або розширити, як вважаєте за потрібне. Ось посилання на джерела . EDIT: Дивіться цей рядок для IExceptionHandlerPathFeature .
— gldraphael

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

Потрібно використовувати в не-ASP.NET контекстах (див. Інші відповіді для ASP.NET Core).

HttpStatusCode- це перерахування в System.Net.


11

Як щодо створення користувацького класу 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 ...але в іншому випадку працював чудово.
— Майк

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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.