Unobserved exception was rethrown despite awaiting the Task and catching Exception - c#

I have code that catches all exceptions that are thrown by a server call as follows:
new public Task SaveAsync()
{
return ServerException.Wrap(base.SaveAsync);
}
Where ServerException.Wrap looks like:
public static async Task<T> Wrap<T>(Func<Task<T>> func)
{
try
{
return await func();
}
catch (Exception ex)
{
// This is an internal error that shouldn't happen.
throw new ServerException(ex);
}
}
public static async Task Wrap(Func<Task> func)
{
await Wrap(async () =>
{
await func();
return true;
});
}
And then I have a function that calls SaveAsync as follows:
try
{
await problem.SaveAsync();
}
catch (ServerException ex)
{
Logger.LogException("Error saving problem.", ex);
}
I have some internal error that generates an exception which I catch in the above line and then it gets logged as follows:
2015-10-20 11:20:44.502 [Line 99] Error saving problem. (Exception:
Exceptions.ServerException: ---> System.ArgumentException: An item
with the same key has already been added. at
System.ThrowHelper.ThrowArgumentException (ExceptionResource resource)
[0x00000] in
/Users/builder/data/lanes/1977/2c66d2fe/source/mono/external/referencesource/mscorlib/system/throwhelper.cs:74
However a few seconds later I get an unhanded exception warning that gets logged:
2015-10-20 11:21:16.352 Warning: Unhandled exception:
System.AggregateException: A Task's exception(s) were not observed
either by Waiting on the Task or accessing its Exception property. As
a result, the unobserved exception was rethrown by the finalizer
thread. ---> System.ArgumentException: An item with the same key has
already been added. at System.ThrowHelper.ThrowArgumentException
(ExceptionResource resource) [0x00000] in
/Users/builder/data/lanes/1977/2c66d2fe/source/mono/external/referencesource/mscorlib/system/throwhelper.cs:74
Why do I get the second unobserved exception, even though I am catching and handling the first exception? This exception seems to be thrown by my ServerException.Wrap method.
I am using MonoTouch.

You need to explicitly set the exception to observed.
For that, you need to subscribe to the TaskScheduler's UnobservedTaskException event, and set it explicitly to observed (call SetObserved() on it).
See here:
UnobservedTaskException being throw...
EDIT:
Of course, you can also just catch AggregateException as well, or use ContinueWith() to observe and resume the task.
See the bottom of the official documentation:
Exception Handling (MSDN)

Related

Would it make sense to always account for multiple exceptions in AggregateExceptions when calling into async code?

When calling into async code like for example productUpdate.UpdateAsync(...), there are chances that it could throw an AggregateException having multiple inner exceptions or just one exception. This all depends on how UpdateAsync was implemented internally.
Question:
Since await unwraps only the first exception in the list of exceptions within an AggregateException, the following special code tries to circumvent that, but this is clunky and ideally in every place where I am calling into some external library's async code, there could be an AggregateException with multiple exceptions. Would it make sense to have this in all those places? (sure probably could move into a helper method but that's not the point here) and also then there's the question of what meaningful things I am doing by catching these exceptions.
I think it does NOT make sense in all places. Your thoughts?
var t1 = FooAsync();
var t2 = BarAsync();
var allTasks = Task.WhenAll(t1, t2);
try
{
await allTasks;
}
catch (Exception)
{
var aggEx = allTasks.Exception as AggregateException;
// todo: do something with aggEx.InnerExceptions
}
Update:
Added whole repro code here for user Dave and the result of running it:
using System;
using System.Threading.Tasks;
class Example
{
static void Main()
{
BlahAsync().Wait();
}
static async Task BlahAsync()
{
var t1 = FooAsync(throwEx: true);
var t2 = BarAsync(throwEx: true);
var allTasks = Task.WhenAll(t1, t2);
try
{
await allTasks;
}
catch (AggregateException agex)
{
Console.WriteLine("Caught an aggregate exception. Inner exception count: " + agex.InnerExceptions.Count);
}
}
static async Task FooAsync(bool throwEx)
{
Console.WriteLine("FooAsync: some pre-await code here");
if (throwEx)
{
throw new InvalidOperationException("Error from FooAsync");
}
await Task.Delay(1000);
Console.WriteLine("FooAsync: some post-await code here");
}
static async Task BarAsync(bool throwEx)
{
Console.WriteLine("BarAsync: some pre-await code here");
if (throwEx)
{
throw new InvalidOperationException("Error from BarAsync");
}
await Task.Delay(1000);
Console.WriteLine("BarAsync: some post-await code here");
}
}
Result:
FooAsync: some pre-await code here
BarAsync: some pre-await code here
Unhandled Exception: System.AggregateException: One or more errors occurred. (Error from FooAsync) ---> System.InvalidOperationException: Error from FooAsync
at Example.<FooAsync>d__2.MoveNext() in C:\Users\foo\source\repos\ConsoleApp9\ConsoleApp9\UnderstandingCallStack.cs:line 37
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Example.<BlahAsync>d__1.MoveNext() in C:\Users\foo\source\repos\ConsoleApp9\ConsoleApp9\UnderstandingCallStack.cs:line 20
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at Example.Main() in C:\Users\foo\source\repos\ConsoleApp9\ConsoleApp9\UnderstandingCallStack.cs:line 8
As mentioned in my comment you can explicitly catch an Aggregate exception like so
try
{
//do you're async code
}
catch (AggregateException ae)
{
//handle it
}
you can add additional catch statements to deal with other exception types, but remember always start with the most specific exception type first and if you have a catch all exception handler (which can be argued you shoudn't but thats not for now) that should always be the last catch statement.
Now when you can catch an AggregateException, as you say, it can contain many exceptions and each of those can contain inner exceptions as well, so it has the potential to be a complete structure of nested exceptions. But don't fear! .NET has provided help. You can called .Flatten() on your aggregate exception. This will return you a new Aggreagete exception that has a flat list of its inner exceptions, not a nested list, so you can easily, iterate over it or just take the top one, whatever you need to do.
try
{
//async code stuff
}
catch(AggregateException ae)
{
var allExceptions = ae.Flatten().InnerExceptions;
// now do what you want with the list of exceptions
}
catch (Exception x)
{
// ooo look here is an example of the second catch statement catching any other exception that isnt an AggregateException)
}
Now another cool thing you can do with aggregate exceptions when you catch them, is pass a custom exception handler to the Handle method on the AE instance. This is useful if you want handle specific kinds of exceptions such as a FileNotFoundException but if there are any other exceptions that should be thrown as another Aggregate Exception for the caller to handle. Like this
try
{
//async stuff
}
catch (AggregateException ae)
{
ae.Handle(x =>
{
if (x is FileNotFoundException)
{
Console.WriteLine("I handled the file not found, don't worry");
return true;
}
return false
});
}
What happens here is that each exception in the Aggregate Exceptions inner exceptions is passed to the handler, we return true, if we handle it and false if we don't. All the exceptions that were not handled (ie we returned false for) are added as the inner exceptions of a new Aggregate exception.
This last part might not be relevant to you, if you just want to the handle the Aggregate exception whatever it contains, but its a good thing to have in the tool box IMO

Exception catched as System.AggregateException

After executing this code:
try
{
DoSomething();
}
catch (TaskCanceledException e)
{
DealWithCancelledTaskException(e);
throw;
}
catch (Exception e)
{
DealWithNormalException(e);
throw;
}
The exception is raised.
DoSomething is supposed to throw TaskCancelledException, but it throws System.AggregateException containing one exception of type TaskCancelledException and is caught as normal Exception.
How can I catch this exception as TaskCancelledException?
It is most likely that your code is throwing an AggregateException
Firstly try explicitly catching AggregateException. Then to access the exception that has been wrapped up by the aggregate exception use the InnerException Property. You can also access the list of all exceptions that have been aggregated (if there is or could be more than 1) by accessing the InnerExceptions property which gives you a list of the exceptions that this exception has aggregated

How to properly catch exceptions from C#'s HttpClient getAsync so the error says more than "One or more errors occurred"?

The following is some code that downloads a file using System.Net.Http.HttpClient
try
{
var responseResult = new System.Net.Http.HttpClient().GetAsync(fileUrl);
using (var memStream = responseResult.Result.Content.ReadAsStreamAsync().Result)
{
using (var fileStream = File.Create(saveToPath))
{
memStream.CopyTo(fileStream);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
Sometimes I call this and a file fails to download. In that situation, the catch is called but doesn't contain any information of the issue:
One or more errors occurred.
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at SpPrefetchIndexBuilder.FileDownloader.StartDownloads(Int32 timeout)
How can I get it to the cause of this exception?
Task.Result throws AggregateException, so you can catch that. All exceptions will be inside InnerExceptions property of that exception (there can be multiple in theory, but in your case there will be just one). First of those exceptions (or the only one if there is just one) is also in InnerException property.
If you don't want to dig inside AggregateException, use .GetAwaiter().GetResult() instead of .Result - this will not wrap exception into AggregateException and will throw it as is.
Since you're calling .Result on the task, original exception will be held in InnerException property of catched exception. You could access it with following construct:
string message = e?.InnerException.Message ?? e.Message;
Not really sure if this applies but have you tried?: Console.WriteLine(ex.GetBaseException().ToString().StackTrace)

Exception Thrown from Thread Pool Thread shown as Unhandled

I am firing off a Task of on a background thread pool thread via the following method
private async Task LoadCoreMatchDataAsync()
{
string errorMessage = String.Empty;
...
try
{
if (!HasConnection)
return;
IProgress<string> progressIndicator = new Progress<string>(LoadProgress);
EventsCollection = new BindableCollection<Taurus.MatchDetails>(
await MatchDataService.GetCollectionAsync(
this.client, progressIndicator, this.token));
...
}
catch (TimeoutException toe)
{
errorMessage = String.Format(
"Retrieval of the MatchDetails using connection " +
"\"{0}\" failed with the following TimeoutException: \"{1}\".",
this.ConnectionString,
toe.Message);
}
catch (OperationCanceledException)
{
// Do nothing, cancel silently.
}
// Display any errors.
if (!String.IsNullOrEmpty(errorMessage))
{
await dialogManager.ShowDialog<MessageDialogResult>(
new MessageBoxViewModel("Connection Timeout", errorMessage, mbs));
HasConnection = false;
}
}
where the GetCollectionAsync(...) method is
public async Task<BindableCollection<Taurus.MatchDetails>> GetCollectionAsync(
MongoClient client, IProgress<string> progressIndicator, CancellationToken token)
{
return await Task.Factory.StartNew<BindableCollection<Taurus.MatchDetails>>(() =>
{
... // Somewhere in here we get a TimeoutException thrown.
}, token);
}
the problem is that when in my call to await MatchDataService.GetCollectionAsync(...) I get an expected TimeoutException, VS2012 throws "a TimeoutException was unhandled by user code" message, when clearly I am handling the exception in the "continuation" in the correct way. If I continue rather than break, the exception is indeed caught and I get my expected error message. I am just not sure why VS2012 is telling me that the exception is unahandled?
I am essentially doing what is described clearly in on of Jon Skeets answers here https://stackoverflow.com/a/19865613/626442.
Thanks for your time.
You have "Just My Code" turned on (which I mentioned in my answer in the other question you reference). The debugger is indicating that "User code" (Your code) did not handle the exception--which is true. The exception is caught by the framework code and placed into a Task.
Turn off the "Just My Code" debugger setting (in my opinion, it is a feature that only causes confusion and has very limited usefulness).

Async/await exception and Visual Studio 2013 debug output behavior

I'm developing an application in C# that communicates with Dynamics NAV through web services. To reduce duplicate code and because there will be many endpoints, I have created a generic async/await method that executes the service calls and handle exceptions.
The method works but I'm seeing an unexpected behavior in the Visual Studio 2013 output window when an exception occur(and is handled).
Test code and output can be seen below.
My concern is the "A first chance exception of type..." lines which I'm seeing 4 times when using the async/await methods. Does this exception really occur 4 times?
When calling the service synchronously there's only one exception line which is expected.
Is this just Visual Studio 2013 or is there something wrong with my async/await code?
Is there maybe a better way of doing what I'm trying to accomplish?
class Program
{
static void Main(string[] args)
{
Debug.WriteLine("Synchronous...");
try
{
TestFunctions_PortClient service = new TestFunctions_PortClient();
service.Open();
string result = service.ErrorTest();
Debug.WriteLine(result);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
Debug.WriteLine(string.Empty);
Debug.WriteLine("Async...");
NavServiceTest navService = new NavServiceTest();
navService.TestAsync();
Console.ReadLine();
}
}
class NavServiceTest
{
public async void TestAsync()
{
try
{
string result = await CallServiceAsync();
Debug.WriteLine(result);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
private async Task<string> CallServiceAsync()
{
TestFunctions_PortClient service = new TestFunctions_PortClient();
service.Open();
ErrorTest_Result result = await ExecuteServiceAsync<ErrorTest_Result>(
service.InnerChannel,
service.Endpoint,
service.ErrorTestAsync());
return result.return_value;
}
private async Task<T> ExecuteServiceAsync<T>(IClientChannel channel, ServiceEndpoint endpoint, Task<T> source)
{
var tcs = new TaskCompletionSource<T>();
Task<T> task = tcs.Task;
try
{
Debug.WriteLine("ExecuteServiceAsync");
tcs.TrySetResult(await source);
}
catch (EndpointNotFoundException ex)
{
Debug.WriteLine("EndpointNotFoundException");
tcs.TrySetException(ex);
}
catch (FaultException ex)
{
Debug.WriteLine("FaultException");
tcs.TrySetException(ex);
}
catch (Exception ex)
{
Debug.WriteLine("Exception");
tcs.TrySetException(ex);
}
finally
{
if (channel != null)
{
if (channel.State == CommunicationState.Faulted)
channel.Abort();
else
channel.Close();
}
}
if (task.IsFaulted)
{
throw task.Exception.InnerException;
}
return task.Result;
}
}
Here's the output of the code above.
Synchronous...
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
Error from NAV
Async...
ExecuteServiceAsync
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
FaultException
A first chance exception of type 'System.ServiceModel.FaultException' occurred in ServiceTest.exe
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
Error from NAV
When an exception occurs in an async method, it doesn't just propagate up the stack like it does in synchronous code. Heck, the logical stack is likely not to be there any more.
Instead, the exception is stored in the task which represents the asynchronous operation. Then, when you await the asynchronous operation, the GetResult method of the TaskAwaiter will rethrow the original exception. If that isn't caught in your code, then it will be caught by the compiler-generated code again and put into the task that represents that operation, etc. So if you have a chain of asynchronous methods (as is often the case) and the deepest one throws an exception, the exception propagation will actually be a "throw in GetResult, catch, stuff into task" per link in the chain.
So yes, the exception is being thrown four times, in order to effectively only be thrown once. If you're worried about the efficiency of that, I suspect it's not too bad - because the logical stack trace is only determined once. I dare say it's less efficient than the synchronous version, but my general philosophy is that if you're seeing so many exceptions that they're affecting your performance significantly, then either you're overusing exceptions or your system is in a really bad state anyway, and performance is the least of your worries.

Categories

Resources