【问题标题】:Exception.GetBaseException() returning exception with not null InnerExceptionException.GetBaseException() 返回不为空的异常 InnerException
【发布时间】:2013-05-10 01:42:41
【问题描述】:

我有这个System.AggregateException 类型的例外:

Message = "One or more errors occurred."
Source = null
StackTrace = null

它的InnerException是这个System.Reflection.TargetInvocationException

Message = "Exception has been thrown by the target of an invocation."
Source = "mscorlib"
StackTrace = 
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.Incoming(IHubIncomingInvokerContext context)

它的InnerException 是我创建的从ApplicationException 扩展的异常:

Message = "Some error writen by me at the hub"
Source = "Chat"
StackTrace = 
      at Chat.Hubs.ChatHub.SendMessage(String text, String clientConnId) in d:\...Chat\Chat\Hubs\ChatHub.cs:line 48

当我运行这个时:

Exception excpetion = ex.GetBaseException();

exSystem.AggregateException 我在excpetion 得到System.Reflection.TargetInvocationException怎么会这样?

场景

我不知道如何在一个简单的项目中重现这一点。就我而言,我在 SignalR 项目中发现了这一点。一些集线器方法抛出异常并在 global.asax 处理错误:

GlobalHost.HubPipeline.AddModule(new MyHubPipelineModule());

MyHubPipelineModule应该是这样的:

public class MyHubPipelineModule : HubPipelineModule
{
    protected override void OnIncomingError(Exception ex, IHubIncomingInvokerContext context)
    {
        Exception excpetion = ex.GetBaseException();
        context.Hub.Clients.Caller.ExceptionHandler(excpetion.Message);
    }
}

注意:这应该使用 SignalR 1.0.1 完成。在 1.1.0 中异常更简单(更小的链)所以它运行良好。确保你有这个包版本:

<package id="Microsoft.AspNet.SignalR" version="1.0.1" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.0.1" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.0.1" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.0.1" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.0.1" targetFramework="net40" />

【问题讨论】:

  • 惊人的问题。因异常而异常。
  • 一个异常类型应该是serializable 如果它跨越了执行上下文边界。不知道 SignalR 是否就是这种情况。

标签: c#-4.0 exception


【解决方案1】:

根据 MSDN GetBaseException 应该表现得像

public Exception GetBaseException()
{ 
    Exception result = this; 
    while (result.InnerException != null) 
        result = result.InnerException; 
    return result; 
}

并声明

对于异常链中的所有异常,GetBaseException 方法必须返回相同的对象(基本异常)。

这就引出了一个问题,为什么这个方法是虚拟的?似乎任何覆盖都只能匹配实现或违反合同。

根据 MSDN AggregateException.GetBaseException

返回作为此异常根本原因的 AggregateException。

根据 OP 的声明(并检查源代码),可能会违反“返回 AggregateException”,因为结果并非始终是 AggregateException。

坦率地说,我认为整个语句是不合逻辑的,因为我认为“第一个”NON-AggregateException 是“这个异常的根本原因”,因为人们可以识别一个单数(“the”)根原因。由于“常规”异常只是在向并行处理“扇出”的根部移动时包装在 AggregateExceptions 中。

我的最好的解释是 AggregateException.GetBaseException 旨在“解开”毫无意义的非并行嵌套 AggregateExceptions,直到达到实际发生“扇出”的级别。

这里的错误(稍后修复)似乎是在没有“扇出”时发生的情况,即只有一个(非聚合)InnerException 的 AggregateException。在这种情况下,它会返回那个(非聚合)异常。 .... 具有不同的 GetBaseException 实现/解释。

2020 年编辑: 在随后几年的某个时间点,AggregateException.GetBaseException's implementation 被修复以匹配上述解释。 @Jan-Slodicka 的回答表明它至少早在 2016 年就已在 Mono 中修复。

【讨论】:

    【解决方案2】:

    这是 Mono 源代码:

    public override Exception GetBaseException() {
        Exception back = this;
        AggregateException backAsAggregate = this;
        while (backAsAggregate != null && backAsAggregate.InnerExceptions.Count == 1) {
            back = back.InnerException;
            backAsAggregate = back as AggregateException;
        }
        return back;
    }
    

    这意味着 GetBaseException() 只是删除最顶层的琐碎 AggregateException 包装器。

    我认为在进行异常报告之前应该始终应用该方法。

    【讨论】:

      【解决方案3】:

      问题似乎与 SignalR 无关。它与AggregateExceptions有关。

      我在查看MSDN page of AggregateException.GetBaseException Method,发现了这个:

      返回作为此异常根本原因的 AggregateException

      所以我猜Exception.GetBaseException Method 的文档只有在方法未被覆盖时才有效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-27
        • 1970-01-01
        • 2014-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多