Where does the async Task throw an Exception if it does not expect it?

I have the following example: (please also read the comments in the code as this will make more sense)

public async Task<Task<Result>> MyAsyncMethod() { Task<Result> resultTask = await _mySender.PostAsync(); return resultTask; // in real-life case this returns to a different assembly which I can't change // but I need to do some exception handling on the Result in here } 

PostAsync _ mySender looks like this:

 public Task<Task<Result>> PostAsync() { Task<Result> result = GetSomeTask(); return result; } 

The question arises:

Since I do not expect the actual Result in MyAsyncMethod , and if the PostAsync method PostAsync an exception, in what context does the exception occur and the exception is handled?

and

Is there a way to handle exceptions in my assembly?

I was surprised when I tried to change MyAsyncMethod to:

  public async Task<Task<Result>> MyAsyncMethod() { try { Task<Result> resultTask = await _mySender.PostAsync(); return resultTask; } catch (MyCustomException ex) { } } 

an exception was caught here, an event if there is no expected actual result. It happens that the result of PostAsync already available, and the exception is correctly selected in this context?

Is it possible to use ContinueWith to handle exceptions in the current class? For example:

 public async Task<Task<Result>> MyAsyncMethod() { Task<Result> resultTask = await _mySender.PostAsync(); var exceptionHandlingTask = resultTask.ContinueWith(t => { handle(t.Exception)}, TaskContinuationOptions.OnlyOnFaulted); return resultTask; } 
+7
c # task-parallel-library async-await
source share
3 answers

These are many questions to pack into one "question", but OK ...

Where does the async Task throw Exception execute if it is not expected?

Unusual task exceptions are TaskScheduler.UnobservedTaskException event. This event is raised β€œin the end,” because the task must actually be garbage collection before its exception is considered unhandled.

Since I do not expect the actual result in the MyAsyncMethod method, and if the PostAsync method throws an exception, in what context will the exception and handling be selected?

Any method that uses the async modifier and returns a Task will put all its exceptions from the returned Task .

Is there a way to handle exceptions in my assembly?

Yes, you could replace the returned task, for example:

 async Task<Result> HandleExceptionsAsync(Task<Result> original) { try { return await original; } catch ... } public async Task<Task<Result>> MyAsyncMethod() { Task<Result> resultTask = await _mySender.PostAsync(); return HandleExceptionsAsync(resultTask); } 

I was surprised that when I tried to change MyAsyncMethod to [synchronously return an internal task], an exception was caught here, even if there was no expected actual result.

This means that the method you are calling is not an async Task , as the sample code shows. This is a non async method, Task returning, and when one of these methods throws an exception, it is handled just like any other exception (i.e., it goes directly up the call stack, does not fit into the returned Task ).

Is it possible to use ContinueWith to handle exceptions in the current class?

Yes, but await cleaner.

+20
source share

I use the extension method for general error handling on Task . This provides the possibility of registering all errors, as well as performing user actions when an error occurs.

 public static async void ErrorHandle(this Task task, Action action = null) { try { await task.ConfigureAwait(false); } catch (Exception e) { Log.Error(e); if (action != null) action(); } } 

I try to use it when I make a β€œfire and forget” Task :

 Task.Run(() => ProcessData(token), token).ErrorHandle(OnError); 
+6
source share

Since I do not expect the actual result in the MyAsyncMethod method, and if the PostAsync method throws an exception, in what context will the exception and handling be selected?

If you do not perform await any of the tasks in your code or assign a continuation, the behavior may vary depending on the version of the .NET framework used. In both cases, the returned Task will swallow the exception, the difference will occur upon completion:

  • .NET 4.0 - the finalizer thread will block the swallowed exception. If the global exception handler is not registered, it will terminate the process

  • .NET 4.5 and higher - the exception will be swallowed and go unnoticed.

In both cases, the TaskScheduler.UnobservedTaskException event raises:

Occurs when an unprotected exception from an unfinished task is about to initiate an exception escalation policy that will terminate the process by default.

When the non- async return method runs synchronously, the exception is thrown immediately, which is why you get the exception without using await , but you should definitely not depend on what is in your code.

Is there a way to handle exceptions in my assembly

Yes, you can. I would advise you await to complete the tasks that you perform inside your assembly.

There is no reason to use the async modifier if you are not expecting anything:

 public Task<Result> PostAsync() { return GetSomeTask(); } 

Then you can await on PostAsync and catch the exception there:

 public async Task<Result> MyAsyncMethod() { try { // No need to use Task<Result> as await will unwrap the outter task return await _mySender.PostAsync(); } catch (MyCustomException e) { // handle here } } 

You can modify this code even further and remove the async and possibly catch an exception, even higher, before calling the method call MyAsyncMethod .

+2
source share

All Articles