I am using a library which provides methods ending with ...Async
and return Task
. I am going to use these in a command line application. So I need to call them synchronously a lot.
C# of course does not allow calling these methods in Main
method since you cannot use async
modifier on Main
method. Assume this is the task:
var task = datastore.Save(data);
I found several solutions like:
Tasks.WaitAll(task); task.Wait();
however all these wrap thrown exceptions in AggregateException
, I don't want that. I just want to say task.Result
and I expect the original exception to be thrown.
When I use a method returning Task<TResult>
, task.Result
throws AggregateException
even though there are no continuation tasks set. Why is this hapening?
I also have tried,
task.RunSynchronously();
it gives error:
RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.
so I guess that's not for methods marked as async
.
Any ideas on patterns using libraries designed for async apps in console apps where there is no asynchronous context?
WhenAll only throws the first exception of the AggregateException stored in task. Exception , even when multiple tasks have faulted.
When awaiting a faulted task (one that has an exception set), await will rethrow the stored exception. If the stored exception is an AggregateException it will rethrow the first and discard the rest.
Exceptions are propagated when you use one of the static or instance Task. Wait methods, and you handle them by enclosing the call in a try / catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, multiple exceptions could be thrown.
AggregateException is used to consolidate multiple failures into a single, throwable exception object. It is used extensively in the Task Parallel Library (TPL) and Parallel LINQ (PLINQ). For more information, see Exception Handling and How to: Handle Exceptions in a PLINQ Query.
I am going to use these in a command line application. So I need to call them synchronously a lot.
No, you don't. You can use async
-await
in a console application, you just need to make an async to sync transition at the very top. And you can do that by using Wait()
:
public static void Main() { MainAsync().Wait(); } public static async Task MainAsync() { var datastore = …; await datastore.SaveAsync(); }
Usually, combining await
with Wait()
is a bad idea (it can cause deadlocks), but it's the right solution here.
Note that if SaveAsync()
throws an exception and you don't catch it, it will be rethrown as AggregateException
from the Wait()
. But you can catch it as the original exception in MainAsync()
(because it doesn't use Wait()
).
If you really wanted to get the first exception thrown directly, you could do something similar to what await
does: task.GetAwaiter().GetResult()
. Note that if the Task
contains more than one exception, you will get only the first one (but the same applies to await
).
Since C# 7.1, you can make your Main
method async
and the compiler will write the transition code for you:
public static async Task Main() { var datastore = …; await datastore.SaveAsync(); }
When I use a method returning
Task<TResult>
,task.Result
throwsAggregateException
even though there are no continuation tasks set. Why is this happening?
This has nothing to do with continuations. A single Task
can represent multiple operations, and each of them can throw an exception. Because of that, Task
methods always throw the exceptions wrapped in an AggregateException
.
I also have tried
task.RunSynchronously()
That doesn't make any sense. RunSynchronously()
can only be used on Task
s that were created using the Task
constructor. That's not the case here, so you can't use it. Task
s returned from async methods are always already started.
You can create a dummy Main
public static void Main() { MainAsync().Wait(); } public static async Task MainAsync() { try { var result = await dataStore.Save(data); } catch(ExceptionYouWantToCatch e) { // handle it } }
Also, see this answer: https://stackoverflow.com/a/9212343/1529246
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With