Como retornar HTTP 500 do ASP.NET Core RC2 Web Api?

189

De volta ao RC1, eu faria o seguinte:

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

No RC2, não há mais HttpStatusCodeResult e não há nada que eu possa encontrar que me permita retornar um tipo 500 de IActionResult.

A abordagem agora é completamente diferente para o que estou perguntando? Não tentamos mais pegar o Controllercódigo? Nós apenas deixamos a estrutura lançar uma exceção genérica de 500 de volta ao chamador da API? Para desenvolvimento, como posso ver a pilha de exceção exata?

Mickael Caruso
fonte

Respostas:

242

Pelo que posso ver, existem métodos auxiliares dentro da ControllerBaseclasse. Basta usar o StatusCodemétodo:

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

Você também pode usar a StatusCode(int statusCode, object value)sobrecarga que também negocia o conteúdo.

Federico Dipuma
fonte
7
fazendo isso, perdemos os cabeçalhos do CORS; portanto, os erros são ocultados nos clientes do navegador. V frustrante.
Bbsimonbb
2
@bbsimonbb Erros internos devem ser ocultados dos clientes. Eles devem ser registrados para desenvolvedores.
Himalaya Garg
10
Os desenvolvedores devem ter, tradicionalmente, a prerrogativa de escolher qual nível de informação de erro será retornada.
precisa saber é o seguinte
179

Você pode usar Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodee Microsoft.AspNetCore.Http.StatusCodesformar sua resposta, se não desejar codificar números específicos.

return  StatusCode(StatusCodes.Status500InternalServerError);

ATUALIZAÇÃO: ago 2019

Talvez não esteja diretamente relacionado à pergunta original, mas ao tentar obter o mesmo resultado Microsoft Azure Functions, descobri que precisava construir um novo StatusCodeResultobjeto encontrado na Microsoft.AspNetCore.Mvc.Coremontagem. Meu código agora se parece com isso;

return new StatusCodeResult(StatusCodes.Status500InternalServerError);
Edward Comeau
fonte
11
Ótimo, evita qualquer parte codificada / "número mágico". Eu usei StatusCode ((int) HttpStatusCode.InternalServerError) antes, mas eu gosto mais do seu.
aleor
1
Uma coisa que eu não considerei na época é que isso torna o código mais legível, voltando a ele, você sabe a que número de erro 500 se refere, está ali no código. Auto-documentando :-)
Edward Comeau
11
Não consigo imaginar o erro interno do servidor (500) mudando tão cedo.
rola
2
impressionante. isso também realmente limpa meus atributos de arrogância. ex: [ProducesResponseType (StatusCodes.Status500InternalServerError)]
redwards510
43

Se você precisar de um corpo em sua resposta, ligue para

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

Isso retornará 500 com o objeto de resposta ...

David McEleney
fonte
3
Se você não deseja criar um tipo de objeto de resposta específico: return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });E, é claro, você pode adicionar uma mensagem descritiva como desejar e outros elementos também.
Mike Taverne
18

Uma maneira melhor de lidar com isso a partir de agora (1.1) é fazer isso em Startup.cs's Configure():

app.UseExceptionHandler("/Error");

Isso executará a rota para /Error . Isso evitará a adição de blocos try-catch a cada ação que você escrever.

Obviamente, você precisará adicionar um ErrorController semelhante a este:

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

Mais informações aqui .


Caso deseje obter os dados reais da exceção, você pode adicioná-los ao acima, Get()antes da returninstrução.

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

Trecho acima retirado do blog de Scott Sauber .

gldraphael
fonte
isso é incrível, mas como posso registrar a exceção lançada?
redwards510
@ redwards510 Veja como fazer isso: scottsauber.com/2017/04/03/... eu vou atualizar a minha resposta para refletir isso, já que é um caso de uso muito comum 😊
gldraphael
@gldraphael Atualmente, estamos usando o Core 2.1. O blog de Scott é ótimo, mas estou curioso para saber se o uso de IExceptionHandlerPathFeature é atualmente as práticas recomendadas. Talvez a criação de middleware personalizado seja melhor?
Pavel
@Pavel, estamos usando o ExceptionHandlermiddleware aqui. Você pode, é claro, fazer o seu próprio ou estendê-lo como achar melhor. Aqui está o link para as fontes . EDIT: Veja esta linha para IExceptionHandlerPathFeature .
Gdraphael # 24/18
15
return StatusCode((int)HttpStatusCode.InternalServerError, e);

Deve ser usado em contextos não-ASP.NET (consulte outras respostas para o ASP.NET Core).

HttpStatusCodeé uma enumeração em System.Net.

Shimmy Weitzhandler
fonte
12

Que tal criar uma classe ObjectResult personalizada que represente um Erro Interno do Servidor como esse OkObjectResult? Você pode colocar um método simples em sua própria classe base para poder gerar facilmente o InternalServerError e retorná-lo da mesma forma que você Ok()ou 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;
    }
}
Airn5475
fonte
6

Quando você deseja retornar uma resposta JSON no MVC .Net Core Você também pode usar:

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

Isso retornará o resultado JSON e HTTPStatus. Eu o uso para retornar resultados para jQuery.ajax ().

Tekin
fonte
1
Eu tive que usar, return new JsonResult ...mas funcionou muito bem.
Mike Taverne
5

Para aspnetcore-3.1, você também pode usar Problem()como abaixo;

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);
}
Teoman shipahi
fonte