Wie kann ich HTTP 500 von ASP.NET Core RC2 Web Api zurückgeben?

185

Zurück in RC1 würde ich das tun:

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

In RC2 gibt es kein HttpStatusCodeResult mehr, und ich kann nichts finden, mit dem ich einen IActionResult-Typ vom Typ 500 zurückgeben kann.

Ist der Ansatz jetzt für das, was ich frage, völlig anders? Versuchen wir nicht mehr, ControllerCode einzufangen ? Lassen wir das Framework nur eine generische 500-Ausnahme an den API-Aufrufer zurückwerfen? Wie kann ich für die Entwicklung den genauen Ausnahmestapel anzeigen?

Mickael Caruso
quelle

Antworten:

236

Soweit ich sehen kann, gibt es in der ControllerBaseKlasse Hilfsmethoden. Verwenden Sie einfach die StatusCodeMethode:

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

Sie können auch die StatusCode(int statusCode, object value)Überladung verwenden, die auch den Inhalt aushandelt.

Federico Dipuma
quelle
7
Dabei verlieren wir die CORS-Header, sodass Fehler vor Browser-Clients verborgen bleiben. V frustrierend.
Bbsimonbb
2
@bbsimonbb Interne Fehler sollten vor Clients verborgen bleiben. Sie sollten für Entwickler protokolliert werden.
Himalaya Garg
10
Entwickler sollten traditionell das Vorrecht haben, zu entscheiden, welche Ebene von Fehlerinformationen zurückgegeben wird.
Bbsimonbb
177

Sie können Ihre Antwort verwenden Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodeund Microsoft.AspNetCore.Http.StatusCodesformulieren, wenn Sie bestimmte Nummern nicht fest codieren möchten.

return  StatusCode(StatusCodes.Status500InternalServerError);

UPDATE: August 2019

Vielleicht nicht direkt mit der ursprünglichen Frage verbunden, aber als Microsoft Azure Functionsich versuchte, das gleiche Ergebnis mit zu erzielen, stellte ich fest, dass ich ein neues StatusCodeResultObjekt konstruieren musste, das in der Microsoft.AspNetCore.Mvc.CoreBaugruppe gefunden wurde. Mein Code sieht jetzt so aus.

return new StatusCodeResult(StatusCodes.Status500InternalServerError);
Edward Comeau
quelle
11
Großartig, vermeidet fest codierte Teile / "magische Zahlen". Ich habe zuvor StatusCode ((int) HttpStatusCode.InternalServerError) verwendet, aber ich mag Ihren besser.
Aleor
1
Eine Sache, die ich damals nicht berücksichtigt habe, ist, dass sie den Code lesbarer macht. Wenn Sie darauf zurückkommen, wissen Sie, worauf sich die Fehlernummer 500 bezieht. Sie befindet sich genau dort im Code. Selbstdokumentierend :-)
Edward Comeau
10
Ich kann mir nicht vorstellen, dass sich der interne Serverfehler (500) bald ändert.
rollt
2
genial. das räumt auch meine Prahlerei-Attribute wirklich auf. Beispiel: [ProducesResponseType (StatusCodes.Status500InternalServerError)]
redwards510
42

Wenn Sie einen Körper in Ihrer Antwort benötigen, können Sie anrufen

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

Dies gibt eine 500 mit dem Antwortobjekt zurück ...

David McEleney
quelle
2
Wenn Sie keinen bestimmten Antwortobjekttyp erstellen möchten: return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });Natürlich können Sie auch eine beliebige beschreibende Nachricht und andere Elemente hinzufügen.
Mike Taverne
17

Ein besserer Weg , dies zu handhaben als jetzt (1.1) ist dies in zu tun Startup.csist Configure():

app.UseExceptionHandler("/Error");

Dadurch wird die Route für ausgeführt /Error. Dies erspart Ihnen das Hinzufügen von Try-Catch-Blöcken zu jeder Aktion, die Sie schreiben.

Natürlich müssen Sie einen ähnlichen ErrorController hinzufügen:

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

Weitere Informationen hier .


Wenn Sie die tatsächlichen Ausnahmedaten abrufen möchten, können Sie diese Get()direkt vor der returnAnweisung oben hinzufügen .

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

Oben ein Ausschnitt aus Scott Saubers Blog .

gldraphael
quelle
Das ist großartig, aber wie kann ich die ausgelöste Ausnahme protokollieren?
redwards510
@ redwards510 So geht's: scottsauber.com/2017/04/03/… Ich werde meine Antwort aktualisieren, um sie wiederzugeben , da es sich um einen sehr häufigen Anwendungsfall handelt 😊
gldraphael
@gldraphael Wir verwenden derzeit Core 2.1. Scotts Blog ist großartig, aber ich bin gespannt, ob die Verwendung von IExceptionHandlerPathFeature derzeit die empfohlenen Best Practices sind. Vielleicht ist es besser, benutzerdefinierte Middleware zu erstellen?
Pavel
@ Pavel wir verwenden hier die ExceptionHandlerMiddleware. Sie können natürlich Ihre eigenen rollen oder sie nach Belieben erweitern. Hier ist der Link zu den Quellen . BEARBEITEN: Siehe diese Zeile für IExceptionHandlerPathFeature .
Gldraphael
15
return StatusCode((int)HttpStatusCode.InternalServerError, e);

Sollte in Nicht-ASP.NET-Kontexten verwendet werden (siehe andere Antworten für ASP.NET Core).

HttpStatusCodeist eine Aufzählung in System.Net.

Shimmy Weitzhandler
quelle
11

Wie wäre es mit dem Erstellen einer benutzerdefinierten ObjectResult-Klasse, die einen internen Serverfehler wie den für darstellt OkObjectResult? Sie können eine einfache Methode in Ihre eigene Basisklasse einfügen, damit Sie den InternalServerError einfach generieren und genau wie Sie Ok()oder zurückgeben können 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
quelle
6

Wenn Sie eine JSON-Antwort in MVC .Net Core zurückgeben möchten, können Sie auch Folgendes verwenden:

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

Dies gibt sowohl das JSON-Ergebnis als auch HTTPStatus zurück. Ich verwende es, um Ergebnisse an jQuery.ajax () zurückzugeben.

Tekin
quelle
1
Ich musste verwenden, return new JsonResult ...aber ansonsten hat es super funktioniert.
Mike Taverne
5

Für aspnetcore-3.1 können Sie auch Problem()wie folgt verwenden ;

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
quelle