Bagaimana cara mengembalikan HTTP 500 dari ASP.NET Core RC2 Web Api?

189

Kembali di RC1, saya akan melakukan ini:

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

Di RC2, tidak ada lagi HttpStatusCodeResult, dan tidak ada yang dapat saya temukan yang memungkinkan saya mengembalikan 500 jenis IActionResult.

Apakah pendekatannya sekarang sama sekali berbeda dengan yang saya tanyakan? Apakah kita tidak lagi mencoba menangkap Controllerkode? Apakah kita membiarkan kerangka kerja melemparkan pengecualian 500 generik kembali ke pemanggil API? Untuk pengembangan, bagaimana saya bisa melihat tumpukan pengecualian yang tepat?

Mickael Caruso
sumber

Jawaban:

242

Dari apa yang saya lihat ada metode pembantu di dalam ControllerBasekelas. Cukup gunakan StatusCodemetode ini:

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

Anda juga dapat menggunakan StatusCode(int statusCode, object value)kelebihan yang juga menegosiasikan konten.

Federico Dipuma
sumber
7
melakukan ini, kami kehilangan header CORS, jadi kesalahan disembunyikan dari klien browser. Sangat frustasi.
bbsimonbb
2
@bbsimonbb Kesalahan internal harus disembunyikan dari klien. Mereka harus dicatat untuk pengembang.
Himalaya Garg
10
Pengembang seharusnya, secara tradisional menikmati, hak prerogatif untuk memilih tingkat informasi kesalahan yang dikembalikan.
bbsimonbb
179

Anda dapat menggunakan Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodedan Microsoft.AspNetCore.Http.StatusCodesuntuk membentuk respons Anda, jika Anda tidak ingin membuat kode angka tertentu.

return  StatusCode(StatusCodes.Status500InternalServerError);

PEMBARUAN: Aug 2019

Mungkin tidak terkait langsung dengan pertanyaan awal tetapi ketika mencoba untuk mencapai hasil yang sama dengan Microsoft Azure Functionssaya menemukan bahwa saya harus membangun StatusCodeResultobjek baru yang ditemukan di Microsoft.AspNetCore.Mvc.Coremajelis. Kode saya sekarang terlihat seperti ini;

return new StatusCodeResult(StatusCodes.Status500InternalServerError);
Edward Comeau
sumber
11
Hebat, hindari bagian-bagian hardcoded / "angka ajaib". Saya telah menggunakan StatusCode ((int) HttpStatusCode.InternalServerError) sebelumnya tetapi saya lebih suka milik Anda.
aleor
1
Satu hal yang saya tidak pertimbangkan pada saat itu adalah membuat kode lebih mudah dibaca, kembali ke sana Anda tahu apa kesalahan nomor 500 terkait, itu ada di sana dalam kode. Mendokumentasikan sendiri :-)
Edward Comeau
11
Saya tidak bisa membayangkan kesalahan server internal (500) berubah dalam waktu dekat.
bergulung
2
luar biasa. ini juga sangat membersihkan atribut angkuh saya. mis: [ProducesResponseType (StatusCodes.Status500InternalServerError)]
redwards510
43

Jika Anda membutuhkan badan dalam respons Anda, Anda dapat menelepon

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

Ini akan menghasilkan 500 dengan objek respons ...

David McEleney
sumber
3
Jika Anda tidak ingin membuat jenis objek respons spesifik: return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });Dan tentu saja, Anda dapat menambahkan pesan yang deskriptif seperti yang Anda inginkan, dan elemen lainnya juga.
Mike Taverne
18

Cara yang lebih baik untuk menangani ini seperti yang sekarang (1,1) adalah untuk melakukan hal ini di Startup.cs's Configure():

app.UseExceptionHandler("/Error");

Ini akan menjalankan rute untuk /Error. Ini akan menyelamatkan Anda dari menambahkan blok try-catch ke setiap tindakan yang Anda tulis.

Tentu saja, Anda harus menambahkan ErrorController yang serupa dengan ini:

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

Informasi lebih lanjut di sini .


Jika Anda ingin mendapatkan data pengecualian yang sebenarnya, Anda dapat menambahkan ini di atas Get()tepat sebelum returnpernyataan.

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

Cuplikan di atas diambil dari blog Scott Sauber .

gldraphael
sumber
ini luar biasa, tetapi bagaimana saya bisa mencatat pengecualian yang dilemparkan?
redwards510
@ redwards510 Begini caranya: scottsauber.com/2017/04/03/... Saya akan memperbarui jawaban saya untuk mencerminkannya, karena ini adalah kasus penggunaan yang sangat umum 😊
gldraphael
@ gldraphael Saat ini kami menggunakan Core 2.1. Blog Scott bagus, tapi saya ingin tahu jika menggunakan IExceptionHandlerPathFeature saat ini merupakan praktik terbaik yang disarankan. Mungkin membuat middleware khusus lebih baik?
Pavel
@Pavel kita menggunakan ExceptionHandlermiddleware di sini. Anda dapat, tentu saja, menggulung sendiri atau memperpanjang sesuai keinginan Anda. Inilah tautan ke sumbernya . EDIT: Lihat baris ini untuk IExceptionHandlerPathFeature .
gldraphael
15
return StatusCode((int)HttpStatusCode.InternalServerError, e);

Harus digunakan dalam konteks non-ASP.NET (lihat jawaban lain untuk ASP.NET Core).

HttpStatusCodeadalah enumerasi di System.Net.

Shimmy Weitzhandler
sumber
12

Bagaimana dengan membuat kelas ObjectResult kustom yang mewakili Galat Server Internal seperti untuk OkObjectResult? Anda dapat menempatkan metode sederhana di kelas dasar Anda sendiri sehingga Anda dapat dengan mudah menghasilkan InternalServerError dan mengembalikannya seperti yang Anda lakukan Ok()atau 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
sumber
6

Saat Anda ingin mengembalikan respons JSON di MVC .Net Core Anda juga dapat menggunakan:

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

Ini akan mengembalikan hasil JSON dan HTTPStatus. Saya menggunakannya untuk mengembalikan hasil ke jQuery.ajax ().

Tekin
sumber
1
Saya harus menggunakan return new JsonResult ...tetapi bekerja dengan baik.
Mike Taverne
5

Untuk aspnetcore-3.1, Anda juga dapat menggunakan Problem()seperti di bawah ini;

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
sumber