簡體   English   中英

ASP.NET Core 相當於 ASP.NET MVC 5 的 HttpException

[英]ASP.NET Core equivalent of ASP.NET MVC 5's HttpException

在 ASP.NET MVC 5 中,您可以使用 HTTP 代碼拋出HttpException ,這將設置響應如下:

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

ASP.NET Core 中不存在HttpException 什么是等效代碼?

我實現了我自己的HttpException和支持中間件,它捕獲所有HttpException並將它們轉換為相應的錯誤響應。 下面可以看到一個簡短的摘錄。 您還可以使用Boxed.AspNetCore Nuget 包。

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

從長遠來看,我建議不要使用異常來返回錯誤。 異常比僅僅從方法返回錯誤要慢。

與 @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>();
    }
}

或者,如果您只想返回任意狀態代碼並且不關心基於異常的方法,則可以使用

return new HttpStatusCodeResult(400);

更新:從 .NET Core RC 2 開始,Http 前綴被刪除。 就是現在:

return new StatusCodeResult(400);

Microsoft.AspNet.Mvc.Controller基類公開HttpBadRequest(string)重載,該重載將錯誤消息返回給客戶端。 因此,從控制器操作中,您可以調用:

return HttpBadRequest("Bad Request.");

最終,我的鼻子說從控制器操作中調用的任何私有方法都應該完全了解 http 上下文並返回IActionResult ,或者執行一些其他小任務,與它位於 http 管道內的事實完全隔離。 當然,這是我個人的意見,但是執行某些業務邏輯的類不應該返回 HTTP 狀態代碼,而應該拋出自己的異常,這些異常可以在控制器/操作級別捕獲和轉換。

ASP.NET Core 本身沒有等價物。 正如其他人所說,實現這一點的方法是使用中間件和您自己的例外。

Opw.HttpExceptions.AspNetCore NuGet 包正是這樣做的。

用於通過 HTTP 返回異常的中間件和擴展,例如作為 ASP.NET Core 問題詳細信息。 問題詳細信息是一種機器可讀格式,用於指定基於https://tools.ietf.org/html/rfc7807 的HTTP API 響應中的錯誤。 但您不僅限於將異常結果作為問題詳細信息返回,還可以為自己的自定義格式創建自己的映射器。

它是可配置的並且有據可查。

以下是現成可用的異常列表:

4xx
  • 400 錯誤請求異常
  • 400 無效模型異常
  • 400 驗證錯誤異常<T>
  • 400 無效文件異常
  • 401 未授權異常
  • 403 禁止異常
  • 404 NotFoundException
  • 404 NotFoundException<T>
  • 409 沖突異常
  • 409 受保護的異常
  • 415 不支持的媒體類型異常
5xx
  • 500 內部服務器錯誤異常
  • 500 數據庫錯誤異常
  • 500 序列化錯誤異常
  • 503 服務不可用異常

從 ASP.NET Core 3 開始,您可以使用ActionResult返回 HTTP 狀態代碼:

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<ITEMS_TYPE> GetByItemId(int id)
{
...
    if (result == null)
    {
        return NotFound();
    }

    return Ok(result);
}

更多細節在這里: https : //docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-3.1

這是@muhammad-rehan-saeed 答案的擴展版本。 它有條件地記錄異常並禁用 http 緩存。
如果你使用這個和 UseDeveloperExceptionPage,你應該之前調用 UseDeveloperExceptionPage。

啟動.cs:

app.UseMiddleware<HttpExceptionMiddleware>();

HttpExceptionMiddleware.cs

/**
 * Error handling: throw HTTPException(s) in business logic, generate correct response with correct httpStatusCode + short error messages.
 * If the exception is a server error (status 5XX), this exception is logged.
 */
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 e)
        {
            var response = context.Response;
            if (response.HasStarted)
            {
                throw;
            }

            int statusCode = (int) e.StatusCode;
            if (statusCode >= 500 && statusCode <= 599)
            {
                logger.LogError(e, "Server exception");
            }
            response.Clear();
            response.StatusCode = statusCode;
            response.ContentType = "application/json; charset=utf-8";
            response.Headers[HeaderNames.CacheControl] = "no-cache";
            response.Headers[HeaderNames.Pragma] = "no-cache";
            response.Headers[HeaderNames.Expires] = "-1";
            response.Headers.Remove(HeaderNames.ETag);

            var bodyObj = new {
                Message = e.BaseMessage,
                Status = e.StatusCode.ToString()
            };
            var body = JsonSerializer.Serialize(bodyObj);
            await context.Response.WriteAsync(body);
        }
    }
}

HTTPException.cs

public class HttpException : Exception
{
    public HttpStatusCode StatusCode { get; }

    public HttpException(HttpStatusCode statusCode)
    {
        this.StatusCode = statusCode;
    }

    public HttpException(int httpStatusCode)
        : this((HttpStatusCode) httpStatusCode)
    {
    }

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

    public HttpException(int httpStatusCode, string message)
        : this((HttpStatusCode) httpStatusCode, message)
    {
    }

    public HttpException(HttpStatusCode statusCode, string message, Exception inner)
        : base(message, inner)
    {
    }

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

我使用此代碼獲得了比使用更好的結果:

  • 使用異常處理程序:
    • 自動記錄每個“正常”異常(例如 404)。
    • 在開發模式下禁用(當 app.UseDeveloperExceptionPage 被調用時)
    • 不能只捕獲特定的異常
  • Opw.HttpExceptions.AspNetCore:當一切正常時記錄異常

另請參閱ASP.NET Core Web API 異常處理

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM