ABP框架下返回ViewResult的控制器动作异常处理方案问询
解决方案:ABP框架下捕获ViewResult控制器异常并写入AbpAuditLogs
一、自定义异常过滤器捕获ViewResult动作异常
ABP默认自动异常处理对返回ViewResult的控制器动作覆盖不足,需自定义异常过滤器针对性捕获:
public class ViewResultExceptionFilter : IAsyncExceptionFilter, ITransientDependency { private readonly IAuditLogManager _auditLogManager; private readonly IExceptionToErrorInfoConverter _errorInfoConverter; private readonly IHttpContextAccessor _httpContextAccessor; public ViewResultExceptionFilter( IAuditLogManager auditLogManager, IExceptionToErrorInfoConverter errorInfoConverter, IHttpContextAccessor httpContextAccessor) { _auditLogManager = auditLogManager; _errorInfoConverter = errorInfoConverter; _httpContextAccessor = httpContextAccessor; } public async Task OnExceptionAsync(ExceptionContext context) { // 仅处理控制器中返回ViewResult的动作异常 if (!(context.ActionDescriptor is ControllerActionDescriptor) || !(context.Result is ViewResult)) { return; } // 标记异常已处理,避免后续逻辑重复处理 context.ExceptionHandled = true; // 将异常详情写入审计日志 var auditLogInfo = await _auditLogManager.GetCurrentAsync(); if (auditLogInfo != null) { // 强制转换异常为包含详情的ErrorInfo,跳过默认配置判断 var errorInfo = _errorInfoConverter.Convert(context.Exception, includeSensitiveDetails: true); auditLogInfo.Exceptions += $"{Environment.NewLine}{errorInfo.ToString()}"; await _auditLogManager.SaveAsync(auditLogInfo); } // 返回友好错误视图,不向客户端暴露异常详情 context.Result = new ViewResult { ViewName = "Error", // 替换为项目中实际的错误页视图名 ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), context.ModelState) { ["ErrorMessage"] = "系统发生错误,请稍后重试" } }; } }
二、注册自定义过滤器
在模块的ConfigureServices方法中注册该过滤器:
public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.Configure<MvcOptions>(options => { options.Filters.Add<ViewResultExceptionFilter>(); }); }
三、绕过AuditLogInfoToAuditLogConverter的配置限制
针对你提到的转换器依赖SendExceptionsDetailsToClients的问题,可重写该转换器强制写入异常详情:
[Dependency(ReplaceServices = true)] public class CustomAuditLogInfoToAuditLogConverter : AuditLogInfoToAuditLogConverter, ITransientDependency { public CustomAuditLogInfoToAuditLogConverter( IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions) : base(exceptionHandlingOptions) { } protected override async Task SetExceptionsAsync(AuditLogInfo auditLogInfo, AuditLog auditLog) { // 忽略原有配置判断,直接将异常详情写入审计日志 if (!string.IsNullOrWhiteSpace(auditLogInfo.Exceptions)) { auditLog.Exceptions = auditLogInfo.Exceptions; } } }
四、关于新增配置选项的建议
你提出的新增AddExceptionDetailsToAuditLogs配置选项的思路合理,当前复用SendExceptionsDetailsToClients确实存在语义不符的问题。可以直接在ABP框架仓库提交Issue提出该需求,或基于现有代码自行扩展配置项。
内容的提问来源于stack exchange,提问作者akinAtak
相关产品推荐
相关产品推荐

