Як повернути 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.