Handle Exceptions with tasks - c#

Say that I have code like this:
serviceCallFinished = false;
Task.Factory.StartNew(() => {
response = ServiceManager.GeneralService.ServiceMethod(loginName, password);
}).ContinueWith(parentTask => { serviceCallFinished = true; });
while (!serviceCallFinished)
Thread.Sleep(100);
if (response.UserValid) { }
In this case the ServiceMethod will throw a Exception but this is never shown, instead I will get a null reference on the response.UserValid?
Why is the exception not handed over to my UI thread?
Note : This is on the UI thread and my idea is to not block the thread during the servicecall.

You don't need to use a flag like that just to wait for an async task to finish. Use Wait()
Task t = Task.Factory.StartNew(() => {
response = ServiceManager.GeneralService.ServiceMethod(loginName, password);
});
try
{
t.Wait();
}
catch (AggregateException e)
{
...
}
the Wait() call will elevate any exceptions within an overall AggregateException.

From the comments and contrary to the example posted, it seems like you want logic that returns to the caller while a response is being awaited, and then do a bunch of stuff afterwards. It also sounds like the stuff afterwards contains a lot of very complex methods that you want to write procedurally. The C# team has heard your problem and many like it and developed the async/await framework that will do exactly that, slated for C# 5. Alternatively, if it is an option for you, there is an AsyncCTP available here: http://www.microsoft.com/download/en/details.aspx?id=9983 HTH.

Look at How to: Handle Exceptions Thrown by Tasks
There is also a good sample.
Wha you could do is basically replace your sleeping loop with:
try
{
task.Wait();
}
catch (AggregateException ae)
{
...
}

Why don't you write code just like this:
Task.Factory.StartNew(() =>
{
response = ServiceManager.GeneralService.ServiceMethod(
loginName, password);
})
.ContinueWith(parentTask => { if (response.UserValid) { } });
It seems more clear and more responsive.

Related

async/wait: bubbleup exceptions?

This pertains to a program that has to collect some info from a server on the web.
Question: How can I get the exceptions from GetServerResponseAsync and Check to bubble up through CheckAsync to the Main program?
As depicted here, they do not. ErrorHandler never gets hit.
My Main program:
....
try
{
Task.Run(() => CheckAsync());
// bubble to here?
ReadConfiguration();
}
catch (Exception ex)
{
// gather and handle all exceptions here
ErrorHandler.NotifyMe(new[] { "some message" }, ErrorType.Stop); // never gets hit
}
public async Task CheckAsync()
{
await GetServerResponseAsync("slm_check"); // may throw exception
...
if (.....)
throw new Exception("...");
...
}
public async Task GetServerResponseAsync(string command)
{
...
// client = HttpClient()
using (apacheResponse = await client.GetAsync(ServerUrl + "...."))
{
if (....)
throw new Exception("Internal web server error", new Exception("Maybe MySQL server is down"));
using (HttpContent content = apacheResponse.Content)
{
if ( ....)
throw new Exception("error message");
}
}
}
How can I get the exceptions from GetServerResponseAsync and Check to bubble up through CheckAsync to the Main program?
Use await to consume your tasks, instead of ignoring them.
Specifically, this line:
Task.Run(() => CheckAsync());
is getting a Task back from the Task.Run method, which is then ignored. Instead of ignoring that task, the code should be awaiting it:
await Task.Run(() => CheckAsync());
As other commenters have pointed out, the Task.Run here doesn't really make sense. If your operation is asynchronous, it shouldn't need to also run on a background thread. Usually. :) So if you take out the Task.Run, your code would look like:
await CheckAsync();
which will properly propagate the exception.

Exception filter for the class many different methods

In my client application that uses webApi I have a plethora of methods that make calls to webApi asynchronously like this:
var task = Task.Run(async () => await this.SaveObject(User));
return task.Result.Content;
The async function can throw an exception if something is wrong with object being saved. In this case my exception will be handled on the client based on it's type. Problem is when async task throws an exception, task.Result.Content buries in within System.AggregateException.
Right now I handle it like this:
try
{
var task = Task.Run(async () => await this.saveObject(User)); return task.Result.Content;
}
catch(AggregateException ex)
{
throw ex.InnerException;
}
I have too many methods that do it the same way. I was wondering if there is a way to avoid using try/catch block in each and every method. Maybe there is an exception filter mechanism, sorta like used on webApi to catch all exceptions within the class in one place? Maybe some attribute I can mark needed methods with?
First off I would recommend that you don't use .Result on a Task. See https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html or https://montemagno.com/c-sharp-developers-stop-calling-dot-result/.
If you follow the above advice and await a Task within a try block, it will throw the actual exception rather than an AggregateException so you might be able to avoid your rethrow code altogether.
Otherwise, if you really want to stick with your .Result code, you can write a generic wrapper method that does common error handling for you:
try
{
var task = Task.Run(async () => await this.Object(User));
return task.Result.Content;
}
catch(AggregateException ex)
{
throw ex.InnerException;
}
To something like:
return RunAsync(() => this.Object(User));
private T RunAsync<T>(Func<Task<T>> func)
{
try
{
var task = Task.Run(func);
return task.Result;
}
catch(AggregateException ex)
{
throw ex.InnerException;
}
}
EDIT:
I've just realised there's another way (see http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html) which is slightly more "hacky" since it feels more hidden but this:
var task = Task.Run(async () => await this.Object(User));
return task.GetAwaiter().GetResult().Content;
The .GetAwaiter().GetResult() will synchronously wait for the Task (as per .Result) but will not wrap any thrown exceptions in an AggregateException - which seems to be your desire.

Async Await Equivalent

When I run this code everything works fine:
public async void InvokePlugin(MyObject xTask)
{
try
{
var hndlr = new TimeoutHandler(RunTask);
var asyncResult = hndlr.BeginInvoke(xTask, null, new object());
if (!asyncResult.AsyncWaitHandle.WaitOne(xTask.Timeout, false))
{
throw new TimeoutException("Plugin didn't complete processing in a timely manner.");
}
hndlr.EndInvoke(asyncResult);
}
catch (Exception ex)
{
//Handle Exceptions
}
}
private delegate void TimeoutHandler(MyObject xTask);
I want to update this code to use Async/Await. I tried doing it like this:
public async void InvokePlugin(MyObject xTask)
{
try
{
var runTask = Task.Run(() => { RunTask(xTask); });
if (await Task.WhenAny(runTask, Task.Delay(xTask.Timeout)) == runTask)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await runTask;
}
else
{
throw new TimeoutException("Plugin didn't complete processing in a timely manner.");
}
}
catch (Exception ex)
{
//Handle Exceptions
}
}
...but it's not working. Clearly I'm doing somethign wring. It does call the RunTask Method and executes the first 2 lines fine but then it just ends and I can't seem to catch the exception in either the TaskRun method or code above. All I see in the Output windows is "Program has exited with code 0 (0x0)."
If the experts out there can either point me to what I'm doing wrong or give me suggestions as to how I can catch the exception and handle it I would be very grateful.
Also if you feel I missed any important details please ask and I will update my question.
Usually I'd say if it works don't fix it but in this case I'm trying to rearchitect a bit to allow for some enhancements so here I am.
Change async void to async Task. See my article on async best practices for more information.
After you do this, consume it asynchronously:
await the task, allowing async to grow.
async and await will naturally grow upward through your code base, until they reach Main, which cannot be async.
In your Main method, call GetAwaiter().GetResult() on the "top" task.
Blocking on asynchronous code is generally not a good idea, but blocking on a single task in a Console app's Main method is an exception to that rule.

Trying to understand Task.ContinueWith()

I'm trying to understand some (in my eyes) weird behaviour. I have a call to some async method and want to retrieve its result. (DeleteIndexAsync return a Task<bool>)
var deleteTask = Task.Run(() => DeleteIndexAsync(localItem))
.ContinueWith(t =>
{
//handle and log exceptions
}, TaskContinuationOptions.OnlyOnFaulted);
if (!deleteTask.Result)
In this scenario Result is false and the Status is WaitingForActivation.
Whereas this code does what I want
var deleteTask = Task.Run(() => DeleteIndexAsync(localItem));
deleteTask.ContinueWith(t =>
{
//handle and log exceptions
return false;
}, TaskContinuationOptions.OnlyOnFaulted);
if (!deleteTask.Result)
Can someone explain why? And is it possible to use async / await instead of Task here?
Edit:
var deleteTask = Task.Run(() => ThrowEx());
bool errorOccurred = false;
deleteTask.ContinueWith(t =>
{
errorOccurred = true;
}, TaskContinuationOptions.OnlyOnFaulted);
if (errorOccurred)
{
return true;
}
If you chain the calls, like in the first example, the value you are assigning to the deleteTask variable is actually the second Task. This is the one that is supposed to run only on failure of the first task (the one calling DeleteIndexAsync).
This is because both Task.Run and Task.ContinueWith return Tasks that they create. It explains why in the first example you get Status == WaitingForActivation. In the first snippet, accessing deleteTask.Result would cause an exception to be thrown. In case DeleteIndexAsync threw, it would be an AggregateException containing original exception (unless you accessed t.Exception), otherwise it would be stating that the "Operation was cancelled" - this is because you try to get the result of the task that was scheduled conditionally and the condition was not met.
If you made method containing the snipped async you could do it like this (not tested):
bool success = false;
try
{
success = await DeleteIndexAsync(localItem);
}
catch (Exception) {}
if (!success)
{
//TODO: handler
}
Regarding question edit:
Using captured variable should help, but your current solution introduces race condition. In this case it would be better to do like this:
var deleteTask = Task.Run(() => ThrowEx());
try
{
deleteTask.Wait();
}
catch (Exception ex)
{
return true;
}
but at this point you can drop the asynchronous call entirely, because you wait for the result immediately - unless this example simplifies work that can be done between Run and Wait)
I have a call to some async method and want to retrieve its result.
The best way to do this is with await, not Result.
Can someone explain why?
In the first example, deleteTask is the task returned from Task.Run. In the second example, deleteTask is the task returned from ContinueWith. This task never actually executes unless DeleteIndexAsync throws an exception.
And is it possible to use async / await instead of Task here?
Yes, that's the best approach. When working with asynchronous code, you should always use await instead of ContinueWith. In this case, the TaskContinuationOptions.OnlyOnFaulted means you should put the continuation code in a catch block after the await:
bool deleteResult;
try
{
deleteResult = await Task.Run(() => DeleteIndexAsync(localItem));
}
catch (Exception ex)
{
//handle and log exceptions
}
if (!deleteResult)
...
Or, since it looks like DeleteIndexAsync is asynchronous, removing Task.Run would be more appropriate:
bool deleteResult;
try
{
deleteResult = await DeleteIndexAsync(localItem);
}
catch (Exception ex)
{
//handle and log exceptions
}
if (!deleteResult)
...

C# How to have a generic method do awaiting?

Okay, bad title, but I couldn't think of a better name..My question isn't probably even specific to async/await, but my question is coming up during async handling, so I'm going to pose it that way:
I have several methods which create lists of tasks and then do an 'await Task.WhenAll(list of tasks)". The specific kind of tasks being awaited on in these methods varies. For example, some methods are awaiting a list of Task<String>, while others are awaiting a list of Task<foo>.
What I'm finding is that I'm needing to do some non-trivial try/catch processing around the Task.WhenAll() in each of these methods, and that code is always the same. I'd like to move that code to a common method, and then pass in the list of tasks and have that common method issue then WhenAll, wrapped up in the try/finally.
But the problem I'm running in to is that each of the methods calling this method will be passing in lists of different Task types, and this causes a compiler complain when I declare the parameter to my common method as just Task:
methodA:
List<Task<String>> myTaskList = ...
ExecuteTasks(myTaskList);
methodB:
List<Task<Foo>> myTaskList = ...
ExecuteTasks(myTaskList);
async Task ExecuteTasks(List<Task> taskList) {
try {
await Task.WhenAll(taskList)
}
catch {
..common catch handling goes here. This handling isn't really sensitive to the
..type of the Tasks, we just need to examine it's Status and Exception properties..
}
}
In the above, methodA and methodB each have their own kinds of task lists that need to be passed in to ExecuteTasks, but the question is how to define the list of tasks to ExecuteTasks so that the compiler doesn't complain about type mismatches? In a non-generic world, I would probably define the parameter to ExecuteTasks a super-class of the the types of list of methodA and methodB so the compiler could "upcast" them, but this approach doesn't seem to work here.. (I tried defining ExecuteTasks as taking a Task<Object> but that didn't solve the type mismatch problem)
Try typing your ExecuteTasks against an IEnumerable<Task> instead:
async Task ExecuteTasks(IEnumerable<Task> taskList) {
As #Hamish Smith pointed out, this is an issue of covariance.
List<Task<String>> myTaskList = ...
ExecuteTasks(myTaskList);
async Task ExecuteTasks(IEnumerable<Task> taskList) {
try {
await Task.WhenAll(taskList)
}
catch {
//..common catch handling goes here. This handling isn't really sensitive to the
//..type of the Tasks, we just need to examine it's Status and Exception properties..
}
}
If it were still typed against List<Task>, then you could do something silly like this:
List<Task<String>> myTaskList = ...
ExecuteTasks(myTaskList);
async Task ExecuteTasks(List<Task> taskList) {
taskList.Add(new Task<int>()) // bad stuff
}
var intTask1 = Task.Run(() => 1);
var intTask2 = Task.Run(() => 2);
var intTasks = new List<Task<int>> { intTask1, intTask2 };
var intExecutor = new TaskExecutor<int>();
await intExecutor.ExecuteTasks(intTasks);
var stringTask1 = Task.Run(() => "foo");
var stringTask2 = Task.Run(() => "bar");
var stringTasks = new List<Task<string>> { stringTask1, stringTask2 };
var stringExecutor = new TaskExecutor<string>();
await stringExecutor.ExecuteTasks(stringTasks);
..................................
class TaskExecutor<T>
{
public async Task ExecuteTasks(IEnumerable<Task<T>> tasks)
{
try
{
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
// Handle exception
}
}
}
While I should really point you at Eric Lippert's series on contra- and co- variance and how generics are seen by the compiler (http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx)...
I do wonder if a generic method would work here?
async Task ExecuteTasks<T>(List<Task<T>> taskList)
{
try
{
await Task.WhenAll(taskList);
}
catch
{
//..common catch handling goes here. This handling isn't really sensitive to the
//..type of the Tasks, we just need to examine it's Status and Exception properties..
}
}

Categories

Resources