web-dev-qa-db-ja.com

ASP.NET MVC 5のHttpExceptionに相当するASP.NET Core

ASP.NET MVC 5では、HTTPコードで HttpException をスローできます。これにより、応答が次のように設定されます。

throw new HttpException((int)HttpStatusCode.BadRequest, "Bad Request.");

HttpExceptionはASP.NET Coreに存在しません。同等のコードは何ですか?

52

独自のHttpExceptionを実装し、すべてのHttpExceptionをキャッチして対応するエラー応答に変換するミドルウェアをサポートしました。以下に短い抜粋を示します。

Boilerplate.AspNetCore Nugetパッケージを使用するか、次のASP.NET MVC Boilerplateで完全なソースコードを表示するか、 GitHub プロジェクトを使用するか、-を使用して新しいプロジェクトを作成できます。 ASP.NET MVC Boilerplate 新しいテンプレートを作成するときにオプションでこの機能を有効にすることができるプロジェクトテンプレート(ボックスをオンにして有効にする)。

// Usage example in Startup.cs
public void Configure(IApplicationBuilder application)
{
    application.UseIISPlatformHandler();

    application.UseStatusCodePagesWithReExecute("/error/{0}");
    application.UseHttpException();

    application.UseMvc();
}

public static class ApplicationBuilderExtensions
{
    public static IApplicationBuilder UseHttpException(this IApplicationBuilder application)
    {
        return application.UseMiddleware<HttpExceptionMiddleware>();
    }
}

internal class HttpExceptionMiddleware
{
    private readonly RequestDelegate next;

    public HttpExceptionMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await this.next.Invoke(context);
        }
        catch (HttpException httpException)
        {
            context.Response.StatusCode = httpException.StatusCode;
            var responseFeature = context.Features.Get<IHttpResponseFeature>();
            responseFeature.ReasonPhrase = httpException.Message;
        }
    }
}

public class HttpException : Exception
{
    private readonly int httpStatusCode;

    public HttpException(int httpStatusCode)
    {
        this.httpStatusCode = httpStatusCode;
    }

    public HttpException(HttpStatusCode httpStatusCode)
    {
        this.httpStatusCode = (int)httpStatusCode;
    }

    public HttpException(int httpStatusCode, string message) : base(message)
    {
        this.httpStatusCode = httpStatusCode;
    }

    public HttpException(HttpStatusCode httpStatusCode, string message) : base(message)
    {
        this.httpStatusCode = (int)httpStatusCode;
    }

    public HttpException(int httpStatusCode, string message, Exception inner) : base(message, inner)
    {
        this.httpStatusCode = httpStatusCode;
    }

    public HttpException(HttpStatusCode httpStatusCode, string message, Exception inner) : base(message, inner)
    {
        this.httpStatusCode = (int)httpStatusCode;
    }

    public int StatusCode { get { return this.httpStatusCode; } }
}
38

@ davidfowlとの簡単なチャット の後、ASP.NET 5にはHttpExceptionHttpResponseExceptionのような概念がなく、「魔法のように」応答メッセージを返すようです。

できることは、 MiddleWare経由でASP.NET 5パイプラインに接続 で、例外を処理するものを作成します。

以下は、エラーハンドラミドルウェアの ソースコード の例です。パイプラインをさらに例外が発生した場合に、応答ステータスコードを500に設定します。

public class ErrorHandlerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ErrorHandlerOptions _options;
    private readonly ILogger _logger;

    public ErrorHandlerMiddleware(RequestDelegate next, 
                                  ILoggerFactory loggerFactory,
                                  ErrorHandlerOptions options)
    {
        _next = next;
        _options = options;
        _logger = loggerFactory.CreateLogger<ErrorHandlerMiddleware>();
        if (_options.ErrorHandler == null)
        {
            _options.ErrorHandler = _next;
        }
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError("An unhandled exception has occurred: " + ex.Message, ex);

            if (context.Response.HasStarted)
            {
                _logger.LogWarning("The response has already started, 
                                    the error handler will not be executed.");
                throw;
            }

            PathString originalPath = context.Request.Path;
            if (_options.ErrorHandlingPath.HasValue)
            {
                context.Request.Path = _options.ErrorHandlingPath;
            }
            try
            {
                var errorHandlerFeature = new ErrorHandlerFeature()
                {
                    Error = ex,
                };
                context.SetFeature<IErrorHandlerFeature>(errorHandlerFeature);
                context.Response.StatusCode = 500;
                context.Response.Headers.Clear();

                await _options.ErrorHandler(context);
                return;
            }
            catch (Exception ex2)
            {
                _logger.LogError("An exception was thrown attempting
                                  to execute the error handler.", ex2);
            }
            finally
            {
                context.Request.Path = originalPath;
            }

            throw; // Re-throw the original if we couldn't handle it
        }
    }
}

そして、あなたはStartUp.csでそれを登録する必要があります:

public class Startup
{
    public void Configure(IApplicationBuilder app, 
                          IHostingEnvironment env, 
                          ILoggerFactory loggerfactory)
    {
       app.UseMiddleWare<ExceptionHandlerMiddleware>();
    }
}
23
Yuval Itzchakov

あるいは、任意のステータスコードを返したいだけで、例外ベースのアプローチに関心がない場合は、次を使用できます。

return new HttpStatusCodeResult(400);

更新:.NET Core RC 2以降、Httpプレフィックスは削除されました。今:

return new StatusCodeResult(400);
12
Jeremy

_Microsoft.AspNet.Mvc.Controller_基本クラスは、エラーメッセージを受け取ってクライアントに返すHttpBadRequest(string)オーバーロードを公開します。したがって、コントローラーアクション内から、次のように呼び出すことができます。

_return HttpBadRequest("Bad Request.");
_

最終的に、コントローラーアクション内から呼び出されるプライベートメソッドは、完全にhttpコンテキストを認識してIActionResultを返すか、httpパイプライン内にあるという事実から完全に隔離された他の小さなタスクを実行する必要があると私の鼻は言います。これは私の個人的な意見ですが、ビジネスロジックの一部を実行するクラスはHTTPステータスコードを返すべきではなく、代わりにコントローラー/アクションレベルでキャッチおよび変換できる独自の例外をスローする必要があります。

8
lc.