You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:53:27