小编典典

ASP.NET Core Web API异常处理

c#

在使用常规ASP.NET Web API多年之后,我将ASP.NET Core用于我的新REST API项目。我看不到任何在ASP.NET Core Web
API中处理异常的好方法。我试图实现异常处理过滤器/属性:

public class ErrorHandlingFilter : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        HandleExceptionAsync(context);
        context.ExceptionHandled = true;
    }

    private static void HandleExceptionAsync(ExceptionContext context)
    {
        var exception = context.Exception;

        if (exception is MyNotFoundException)
            SetExceptionResult(context, exception, HttpStatusCode.NotFound);
        else if (exception is MyUnauthorizedException)
            SetExceptionResult(context, exception, HttpStatusCode.Unauthorized);
        else if (exception is MyException)
            SetExceptionResult(context, exception, HttpStatusCode.BadRequest);
        else
            SetExceptionResult(context, exception, HttpStatusCode.InternalServerError);
    }

    private static void SetExceptionResult(
        ExceptionContext context, 
        Exception exception, 
        HttpStatusCode code)
    {
        context.Result = new JsonResult(new ApiResponse(exception))
        {
            StatusCode = (int)code
        };
    }
}

这是我的启动过滤器注册:

services.AddMvc(options =>
{
    options.Filters.Add(new AuthorizationFilter());
    options.Filters.Add(new ErrorHandlingFilter());
});

我遇到的问题是,当发生异常时,AuthorizationFilter它不会由处理ErrorHandlingFilter。我期望它会像在旧的ASP.NET
Web API中一样被捕获。

那么,如何捕获所有应用程序异常以及动作过滤器中的任何异常?


阅读 926

收藏
2020-05-19

共1个答案

小编典典

异常处理中间件

在使用不同的异常处理方法进行了许多实验之后,我最终使用了中间件。对于我的ASP.NET Core Web
API应用程序,它表现得最好。它可以处理应用程序异常以及动作过滤器中的异常,并且我可以完全控制异常处理和HTTP响应。这是我的异常处理中间件:

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate next;
    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context /* other dependencies */)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception ex)
    {
        var code = HttpStatusCode.InternalServerError; // 500 if unexpected

        if      (ex is MyNotFoundException)     code = HttpStatusCode.NotFound;
        else if (ex is MyUnauthorizedException) code = HttpStatusCode.Unauthorized;
        else if (ex is MyException)             code = HttpStatusCode.BadRequest;

        var result = JsonConvert.SerializeObject(new { error = ex.Message });
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)code;
        return context.Response.WriteAsync(result);
    }
}

在课堂上 在MVC之前 注册Startup

app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseMvc();

您可以添加堆栈跟踪,异常类型名称,错误代码或您想要的任何内容。非常灵活。这是异常响应的示例:

{ "error": "Authentication token is not valid." }

考虑序列化响应对象以利用ASP.NET
MVC的序列化设置在所有端点之间实现更好的序列化一致性时,考虑注入IOptions<MvcJsonOptions>Invoke方法,然后使用该方法JsonConvert.SerializeObject(errorObj, opts.Value.SerializerSettings)

方法2

UseExceptionHandler对于简单的方案,还有另一个非显而易见的API 可以正常工作:

app.UseExceptionHandler(a => a.Run(async context =>
{
    var feature = context.Features.Get<IExceptionHandlerPathFeature>();
    var exception = feature.Error;

    var result = JsonConvert.SerializeObject(new { error = exception.Message });
    context.Response.ContentType = "application/json";
    await context.Response.WriteAsync(result);
}));

这不是设置异常处理的非常明显但简单的方法。但是,我仍然更喜欢中间件方法,因为我获得了更多控制权并具有注入必要依赖项的能力。

2020-05-19