【问题标题】:Handling exceptions thrown by ASP.NET Core filters处理 ASP.NET Core 过滤器抛出的异常
【发布时间】:2021-05-19 04:58:56
【问题描述】:

我使用了很多 asp.net 核心过滤器。
我正在寻找优雅的方式来处理过滤器可能抛出的异常。

例如这样的过滤器:

public async void OnAuthorization(AuthorizationFilterContext context){
     Convert.ToInt32("NotConvertable");
}

会抛出 FormatException ,这会破坏整个应用程序,这并不酷。 我想记录错误,返回 500 但没有应用迷恋。

我尝试在MVC之前添加中间件:

try
{
    await _next(context);
}
catch (Exception ex)
{
    _logger.LogError("FATAL ERROR", ex);
}

但它没有帮助,仍然粉碎。

我正在考虑 make try{}catch 并返回 500 并在每个过滤器中记录某种日志,但这会导致大量重复。

有什么办法可以全局处理吗?

更多上下文

  public class PermissionAttribute:TypeFilterAttribute
  {
       public PermissionAttribute():base(typeof(PermissionFilter))
       {
       }
  }

 public class PermissionFilter : IAuthorizationFilter
 {
      public async void OnAuthorization(AuthorizationFilterContext context)
      {
           Convert.ToInt32("NotConvertable");
      }
 }

和控制器:

[Route("api/nav/")]
public class AController : Controller{

    ...

    [HttpGet]
    [Route("{id}")]
    [PermissionAttribute]
    [ProducesResponseType(typeof(SomeClass), 200)]
    public async Task<SomeClass> GetAll()
    {
         ...
    }
}

调用这个端点crush整个过程

Startup.cs(短路) public void Configure(...一些服务){

... some app.Use UseLogger, HealthCheck
app.UseMiddleware<PleaseDontCrushMiddleware>(); // Middleware mentioned above
app.UseExceptionHandler(errorHandler.Handle);

a lot of middlewares

app.UseMvc(RouteTable);

}

MVC 服务是这样添加的:

services.AddMvc(config =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            config.Filters.Add(new AuthorizeFilter(policy));
            config.Filters.Add(new ResponseCacheFilter(new CacheProfile()
            {
                NoStore = true,
                Location = ResponseCacheLocation.None
            }, 
            services.BuildServiceProvider().GetService<ILoggerFactory()));
         }

【问题讨论】:

  • @pinkfloydx33 已编辑,我使用 ASP.NET Core
  • 您能否展示您的 Startup.cs 和 Controller 使用过滤器的位置 - 给我们更多的上下文?
  • @IMujagic 扩展
  • 抱歉,我没有看到您的 Startup.cs。但总的来说,请确保您的异常中间件是管道中的第一个。请记住,在 Startup.cs 中注册中间件时,顺序很重要
  • @IMujagic 我有很多中间件,但异常处理在大多数中间件之前。当我使用调试器时,我在调用堆栈中有我的中间件调用 _next

标签: c# asp.net-core filter error-handling


【解决方案1】:

假设您将在某些方法中抛出一些特定的异常,而您只想将其捕获为 System.Exception,也许您可​​以使用这种方法:

您可以创建异常处理扩展方法(如果您也想使用 Logger,只需在方法中添加 ILogger 参数并从 Startup.Configure 传递它):

public static class ExceptionHandler
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        public static void UseCustomExceptionHandler(this IApplicationBuilder app)
        {
            app.UseExceptionHandler(eApp =>
            {
                eApp.Run(async context =>
                {
                    context.Response.StatusCode = 500;
                    context.Response.ContentType = "application/json";

                    var errorCtx = context.Features.Get<IExceptionHandlerFeature>();
                    if (errorCtx != null)
                    {
                        var ex = errorCtx.Error;
                        var message = "Unspecified error ocurred.";
                        var traceId = traceIdentifierService.TraceId;

                        if (ex is ValidationException)
                        {
                            var validationException = ex as ValidationException;
                            context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                            message = string.Join(" | ", validationException.Errors.Select(v => string.Join(",", v.Value)));
                        }
                        else if (ex is SomeCustomException)
                        {
                            var someCustomException = ex as SomeCustomException;
                            ...
                        }

                        var jsonResponse = JsonConvert.SerializeObject(new ErrorResponse
                        {
                            TraceId = traceId,
                            Message = message
                        });
                        await context.Response.WriteAsync(jsonResponse, Encoding.UTF8);
                    }
                });
            });
        }
    }

然后你只需在 Startup Configure 中注册它:

public void Configure(IApplicationBuilder app)
        {
            ...

            app.UseCustomExceptionHandler();

            ...
        }

关于授权过滤器中的异常(来自微软文档):

不要在授权过滤器中抛出异常:

The exception will not be handled.
Exception filters will not handle the exception.

考虑在一个异常发生时发出一个质询 授权过滤器

您可以在此处阅读更多信息:https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1#action-filters

【讨论】:

  • 我正在使用自定义的 ExceptionHandler,但是当异常来自过滤器/属性时它不会被调用。进程在它之前死亡
  • 我更新了我的答案。您不应该从授权过滤器中抛出异常,它们不会被处理。检查我更新的答案。
猜你喜欢
  • 2015-12-12
  • 2021-11-12
  • 2020-07-14
  • 2018-12-27
  • 2017-06-29
  • 2016-06-14
  • 1970-01-01
  • 2013-07-24
  • 2021-08-09
相关资源
最近更新 更多