Exception.GetBaseException() returning exception with not null InnerException

匆匆过客 提交于 2020-06-12 02:04:18

问题


I've this exception of type System.AggregateException:

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

It's InnerException is this 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)

It's InnerException is this exception created by me that extends from 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

When I run this:

Exception excpetion = ex.GetBaseException();

Where ex is the System.AggregateException I get the System.Reflection.TargetInvocationExceptionat excpetion. How can this happen?

Scenario

I don't know how to reproduce this in a simple project. In my case I found this with a SignalR project. Some hub method throwing an exception an handle the errors with this at the global.asax:

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

And MyHubPipelineModule should be like this:

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

Note: This should be done with SignalR 1.0.1. In the 1.1.0 The exception is simpler (smaller chain) so it works well. Make sure you have this packages versions:

<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" />

回答1:


According to MSDN GetBaseException should behave like

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

And states

For all exceptions in a chain of exceptions, the GetBaseException method must return the same object (the base exception).

Which begs the question, why is this method virtual? It would seem that any override could only match the implementation or violate the contract.

According to MSDN AggregateException.GetBaseException

Returns the AggregateException that is the root cause of this exception.

By the OP's statement (and inspection of the source), "Returns the AggregateException" can be violated because the result is not always an AggregateException.

Frankly, I find the whole statement to be a non-sequitur as I would consider the 'first' NON-AggregateException to be "the root cause of this exception" insofar as one can identify a singular ("the") root cause. Since "regular" exceptions just get wrapped in AggregateExceptions as one moves toward the root of a parallel processing 'fan out'.

My best interpretation is that AggregateException.GetBaseException is intended to "unwrap" pointlessly non-parallel nested AggregateExceptions until reaching a level where 'fan out' actually occurs.

The bug here (LATER FIXED) would appear to be what happens when there IS no 'fan out', i.e. an AggregateException with just one (non-Aggregate) InnerException(s). In that case it returns that (non-Aggregate) Exception. .... which has a different GetBaseException implementation/interpretation.

EDIT 2020: At some point in the intervening years AggregateException.GetBaseException's implementation was fixed to match the above interpretation. @Jan-Slodicka's answer indicates it was fixed at least in Mono as far back as 2016.




回答2:


It seemed that the problem wasn't linked with SignalR. It has to do with AggregateExceptions.

I was looking at the MSDN page of AggregateException.GetBaseException Method and I found this:

Returns the AggregateException that is the root cause of this exception

So I guess that the documentation of Exception.GetBaseException Method is valid only if the method is not overridden.




回答3:


This is the Mono source code:

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;
}

It means GetBaseException() just removes topmost trivial AggregateException wrappers.

It my opinion the method should be always applied before making exception report.



来源:https://stackoverflow.com/questions/16565834/exception-getbaseexception-returning-exception-with-not-null-innerexception

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!