c# - 在不跳过 OutputFormatter 的情况下捕获异常并使用自定义消息进行响应

标签 c# asp.net-core-webapi .net-6.0

我正在开发 WebAPI 并希望捕获我所有的 ApiException 自定义异常并显示 WebAPI 友好的响应。 ApiException 异常可以从 ActionFilter 中抛出,例如 IAuthorizationFilterActionFilterAttribute

首先我尝试使用 IExceptionFilter 但后来我发现 IExceptionFilter 只处理从 Actions 而不是从其他 Filters 抛出的异常。

public class ApiExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
    
        var exception = context.Exception;
    
        if (exception is not ApiException responseException)
        {
            responseException = new ApiException(ResponseMessageType.UnhandledException);
        }
    
        context.Result = new ObjectResult(new ResultMessageDto(responseException))
        {
            StatusCode = responseException.HttpStatusCode
        };
    }
    
}

我发现很多人建议使用的第二种方法是中间件,但这不是 WebAPI 设计的正确方法。

    public class ErrorHandlerMiddleware
    {
        private readonly RequestDelegate _next;
    
        public ErrorHandlerMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception exception)
            {
                var response = context.Response;
                response.ContentType = "application/json";
    
                if (exception is not ApiException responseException)
                {
                    responseException = new ApiException(ResponseMessageType.UnhandledException);
                }
    
                response.StatusCode = responseException.HttpStatusCode;
                await response.WriteAsJsonAsync(new ResultMessageDto(responseException), new JsonSerializerOptions()
                {
                    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
                    PropertyNamingPolicy = null
                });
            }
    }
}

中间件异常处理会跳过 WebAPI MVC OutputFormaters 并仅以 JSON 或开发人员设置的内容进行响应。这个解决方案在设计上很糟糕,因为不尊重 Accept header 。

如何在 ActionsFilters 中处理 Exceptions 而无需 leaving MVC scope

最佳答案

我觉得最好在中间件中处理,这里是一个示例代码。我使用的是 Json,但在这里,您可以使用任何输出格式化程序(甚至是自定义的)。

 public async Task InvokeAsync(HttpContext context, RequestDelegate next)
 {
    try
    {
        await next(context);
    }
    catch (Exception ex)
    {
         await HandleExceptionAsync(context, ex);
    }
}

private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
   int statusCode = StatusCodes.Status500InternalServerError;
   string exceptionType, exceptionDetail;
   context.Response.ContentType = "application/json";

   switch (exception)
   {
    case ArgumentNullException:
          exceptionType = "Argument Null Exception";
          exceptionDetail = exception.Message;
          break;
      case ApiException:
          exceptionType = "API Exception";
          exceptionDetail = exception.Message;
          break;
   default:
          exceptionType = "Unhandled"
          exceptionDetail = "Something went wrong";
          break;
   }

    var problemDetails = new Microsoft.AspNetCore.Mvc.ProblemDetails
    {
        Status = statusCode,
        Type = exceptionType,
        Title = "An error has occurred within the PromComm Application",
         Detail = exceptionDetail,
         Instance = context.Request.Path
     };

    // You can use any formatter here even with custom messages
     var problemDetailsJson = System.Text.Json.JsonSerializer.Serialize(problemDetails);

     context.Response.StatusCode = statusCode;
     await context.Response.WriteAsync(problemDetailsJson);
}

关于c# - 在不跳过 OutputFormatter 的情况下捕获异常并使用自定义消息进行响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73812033/

相关文章:

c# - 使用正则表达式匹配但不包含在结果中

C#实现两个不同的泛型接口(interface)

c# - 使用 MVVM 时我应该在哪个类中加载数据

asp.net-core-webapi - 在大型应用程序中指定路由的最佳实践

c# - 尝试使用 Hangfire 时的自引用循环

c# - .NET 5 到 .NET 6 迁移 - 如何修复迁移后 appsettings.json 数据被读取为 NULL 的问题?依赖注入(inject)不起作用

c# - C# 2.0 可以创建发光效果吗?

entity-framework - OData 与 EF Core/ASP.NET Core - 好还是坏?

具有 Azure SQL DB(托管标识)的 Azure 应用服务

c# - Web API Asp.Net 6 路由说明