问题
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.TargetInvocationException
at 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