ASP.NET Core RC2 Web APIからHTTP 500を返す方法は?


189

RC1に戻ると、次のようにします。

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

RC2では、HttpStatusCodeResultはなくなり、500タイプのIActionResultを返すことができるものはありません。

今私が求めているものとはまったく異なるアプローチですか?Controllerコードでtry-catchしなくなりましたか?フレームワークにAPI呼び出し元に一般的な500例外をスローさせるだけですか?開発の場合、どのようにして正確な例外スタックを確認できますか?

回答:


242

私が見ることができるものから、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 2018年

2
@bbsimonbb内部エラーはクライアントから隠されるべきです。それらは開発者のためにログに記録する必要があります。
Himalaya Garg

10
開発者は、伝統的に楽しんでいる、返されるエラー情報のレベルを選択する特権を持っている必要があります。
bbsimonbb 2018

179

特定の番号をハードコード化したくない場合は、Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodeおよびMicrosoft.AspNetCore.Http.StatusCodesを使用して応答を形成できます。

return  StatusCode(StatusCodes.Status500InternalServerError);

更新:2019年8月

おそらく元の質問に直接関係しているわけではありませんが、同じ結果を達成しようとすると、アセンブリーにMicrosoft Azure Functionsある新しいStatusCodeResultオブジェクトを作成する必要があることがわかりましたMicrosoft.AspNetCore.Mvc.Core。私のコードは次のようになります。

return new StatusCodeResult(StatusCodes.Status500InternalServerError);

11
すばらしい。ハードコードされたパーツ/「マジックナンバー」を回避する。私は以前にStatusCode((int)HttpStatusCode.InternalServerError)を使用しましたが、あなたの方が好きです。
aleor

1
当時、私が考慮していなかったことの1つは、コードを読みやすくすることです。それに戻って、エラー番号500が何に関連するかを知っています。それはコードの中にあります。自己文書化:-)
Edward Comeau

11
内部サーバーエラー(500)がすぐに変わるとは思えません。
ロール

2
驚くばかり。これにより、私のswagger属性も本当にクリーンアップされます。例:[ProducesResponseType(StatusCodes.Status500InternalServerError)]
redwards510 '19年

43

応答に本文が必要な場合は、

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

これは、応答オブジェクトとともに500を返します...


3
特定の応答オブジェクトタイプを作成したくない場合:return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });もちろん、必要に応じてメッセージやその他の要素を追加することもできます。
Mike Taverne、

18

今のところ、これを処理するためのより良い方法(1.1)でこれを行うことですStartup.csさんConfigure()

app.UseExceptionHandler("/Error");

これはのルートを実行し/Errorます。これにより、作成するすべてのアクションにtry-catchブロックを追加する必要がなくなります。

もちろん、次のような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 2017年

redwards510 @ここではあなたがそれを行う方法は次のとおりです。scottsauber.com/2017/04/03/...それは非常に一般的なユースケースなので、私はそれを反映するために私の答えを更新します😊
gldraphael

@gldraphael現在、Core 2.1を使用しています。Scottのブログはすばらしいですが、IExceptionHandlerPathFeatureを使用することが現在推奨されているベストプラクティスであるかどうか知りたいです。おそらくカスタムミドルウェアを作成する方が良いでしょうか?
Pavel

@Pavel ExceptionHandlerここでミドルウェアを使用しています。もちろん、自分でロールすることも、必要に応じて拡張することもできます。ここにソースへリンクがあります。編集:については、この行参照してくださいIExceptionHandlerPathFeature
gldraphael

15
return StatusCode((int)HttpStatusCode.InternalServerError, e);

ASP.NET以外のコンテキストで使用する必要があります(ASP.NET Coreの他の回答を参照してください)。

HttpStatusCodeはの列挙ですSystem.Net


12

のような内部サーバーエラーを表すカスタム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

MVC .Net CoreでJSON応答を返したい場合は、以下も使用できます。

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

これは、JSON結果とHTTPStatusの両方を返します。結果をjQuery.ajax()に返すために使用します。


1
私は使用しreturn new JsonResult ...なければなりませんでしたが、それ以外はうまくいきました。
Mike Taverne、

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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.