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?

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.


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

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 ...


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 .


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.


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

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 ().


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);
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.