.NET WebAPI中如何禁用外部库的ExceptionFilterAttribute
解决方案
针对你遇到的外部库全局异常过滤器日志级别问题,有两种可行方案,可根据实际场景选择:
方案一:重写过滤器逻辑(适合需保留原过滤器其他业务逻辑的场景)
如果原过滤器除日志外还有必须保留的逻辑(比如设置响应状态码),可以继承原过滤器并重写OnException方法,替换全局过滤器注册:
- 创建自定义过滤器类,继承外部库的
GlobalExceptionFilter:
public class CustomGlobalExceptionFilter : GlobalExceptionFilter { private readonly ILogger<CustomGlobalExceptionFilter> _logger; public CustomGlobalExceptionFilter(ILogger<CustomGlobalExceptionFilter> logger) : base(logger) { _logger = logger; } public override void OnException(ExceptionContext context) { // 替换成你实际触发400响应的业务异常类型 if (context.Exception is BadRequestBusinessException badRequestEx) { // 记录Info级日志 _logger.LogInformation(badRequestEx, badRequestEx.Message); // 复制原过滤器中除LogError外的其他逻辑(比如设置400响应) context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; context.Result = new JsonResult(new { Error = badRequestEx.Message }); context.ExceptionHandled = true; } else { // 其他异常沿用原过滤器的Error日志和逻辑 base.OnException(context); } } }
- 在Program.cs中替换全局过滤器:
builder.Services.AddControllers(options => { // 移除外部库注册的原过滤器 var originalFilter = options.Filters.FirstOrDefault(f => f is ServiceFilterAttribute sf && sf.ServiceType == typeof(GlobalExceptionFilter)); if (originalFilter != null) { options.Filters.Remove(originalFilter); } // 添加自定义过滤器 options.Filters.Add<CustomGlobalExceptionFilter>(); });
方案二:拦截日志输出(适合无需修改过滤器逻辑,仅调整日志级别的场景)
如果只需要修改日志级别,不想改动过滤器的业务逻辑,可以通过自定义日志过滤器拦截GlobalExceptionFilter的日志输出:
- 创建日志级别拦截器:
public class CustomLogLevelInterceptor : ILoggerProvider { private readonly ILoggerProvider _innerProvider; public CustomLogLevelInterceptor(ILoggerProvider innerProvider) { _innerProvider = innerProvider; } public ILogger CreateLogger(string categoryName) { var innerLogger = _innerProvider.CreateLogger(categoryName); // 只拦截GlobalExceptionFilter的日志 if (categoryName == typeof(GlobalExceptionFilter).FullName) { return new LevelAdjustingLogger(innerLogger); } return innerLogger; } public void Dispose() => _innerProvider.Dispose(); private class LevelAdjustingLogger : ILogger { private readonly ILogger _innerLogger; public LevelAdjustingLogger(ILogger innerLogger) { _innerLogger = innerLogger; } public IDisposable BeginScope<TState>(TState state) => _innerLogger.BeginScope(state); public bool IsEnabled(LogLevel logLevel) => _innerLogger.IsEnabled(logLevel); public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { // 当是Error日志且异常为触发400的业务异常时,改为Info级别 if (logLevel == LogLevel.Error && exception is BadRequestBusinessException) { _innerLogger.Log(LogLevel.Information, eventId, state, exception, formatter); } else { _innerLogger.Log(logLevel, eventId, state, exception, formatter); } } } }
- 在Program.cs中注册拦截器:
builder.Services.PostConfigure<LoggerFilterOptions>(options => { var originalProviders = options.LoggerProviders.ToList(); options.LoggerProviders.Clear(); foreach (var provider in originalProviders) { options.LoggerProviders.Add(new CustomLogLevelInterceptor(provider)); } });
注意:上述代码中的BadRequestBusinessException需要替换成你实际触发400响应的业务异常类型。
内容的提问来源于stack exchange,提问作者Laser Ayyıldız
相关产品推荐
相关产品推荐

