Does I deal with all possible exceptions?
-
Monday, February 13, 2012 7:33 AM
Snippet as below:
public Task SomeFunc() { TaskCompletionSource<string> tcs = new TaskCompletionSource<string>(); Task task1 = TaskOne(); task1.ContinueWith((t) => { MyExceptionWriter(t); string result = TaskTwo().Result; //how to capture possible exceptions of TaskTwo? tcs.TrySetResult(result); }); return tcs.Task; }Or I have to do as below:
public Task SomeFunc() { TaskCompletionSource<string> tcs = new TaskCompletionSource<string>(); Task task1 = TaskOne(); task1.ContinueWith((t) => { MyExceptionWriter(t); Task task2 = TaskTwo(); MyExceptionWriter(result); string result = task2.Result; tcs.TrySetResult(result); }); return tcs.Task; }What's the best solution? Thanks.
All Replies
-
Monday, February 13, 2012 10:28 AM
I think you can use conditional task continuations. Define two task continuations for task2 as below:
task2.ContinueWith(ant => tcs.TrySetException(ant.Exception), TaskContinuationOptions.OnlyOnFaulted); task2.ContinueWith(ant => tcs.TrySetResult(ant.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
-
Tuesday, February 28, 2012 8:14 PMOwner
If your goal is to have any exceptions from task1 show up on tcs.Task, you need to manually transfer those exceptions over, e.g.
public Task SomeFunc()
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
Task<Whatever> task1 = TaskOne();
task1.ContinueWith((t) =>
{
if (t.IsFaulted) tcs.SetException(t.Exception.InnerExceptions);
else if (t.IsCanceled) tcs.SetCanceled();
else
{
try
{
string result = Process(t.Result);
tcs.SetResult(result);
}
catch(Exception e) { tcs.SetException(e); }
}
});
return tcs.Task;
}- Proposed As Answer by Stephen Toub - MSFTMicrosoft Employee, Owner Tuesday, February 28, 2012 8:14 PM
-
Thursday, March 01, 2012 2:48 AM
Hi, Stephen.
To make my question clear, I rewrite the code as below:
public Task TaskThree(){ ... return Task.Factory.StartNew(() => { ... Task task1 = TaskOne(); task1.ContinueWith((t) => { string result = TaskTwo().Result; }); }); } public void Caller(){ Task someTask = TaskThree(); try { TaskThree.Result; //or TaskThree.Wait(), are they identical? } catch(AggregateException aex) { foreach(Exception ex in aex.Flatten().InnerExceptions) { MyExceptionWriter(ex); //Does here write all possible excetion in TaskOne, TaskTwo and TaskThree? } } }Additionally, the book of "CSharp 4.0 in a Nutshell" said:
You still need to exception-handle detached autonomous tasks (unparented tasks that are not waited upon) in order to prevent an unhandled exception taking down the application when the task drops out of scope and is garbage-collected(subject to the following note). The same applies for tasks waited upon with a time-out, because any exception thrown after the timeout interval will otherwise be "unhandled."
The static TaskScheduler.UnobservedTaskException event provides a final last resort for dealing with unhandled task exceptions. By handling this event, you can intercept task exceptions that would otherwise end the application—and provide your own logic for dealing with them.
Can anybody tell me how to deal with the TaskScheduler.UnobservedTaskException event?
Thanks.
-
Thursday, March 01, 2012 6:00 AMOwner
re: "or TaskThree.Wait(), are they identical?"
You can think of Result as just calling Wait and then returning the stored result.
re: "Does here write all possible excetion in TaskOne, TaskTwo and TaskThree?"
No. You never waited on task #1 or accessed its Result or exception, and any exception that emerged from TaskTwo().Result would just propagate and get stored into the continuation task (task1.ContinueWith), which you're ignoring. If you want TaskThree.Result to throw with all possible exceptions, you could either create both TaskOne and task1.ContinueWith as TaskCreationOptions.AttachedToParent, or you could change the code in TaskThree to be:
return Task.Factory.StartNew(() =>
{
...
Task task1 = TaskOne();
return task1.ContinueWith((t) =>
{
t.Wait();
string result = TaskTwo().Result;
});
}).Unwrap();re: "Can anybody tell me how to deal with the TaskScheduler.UnobservedTaskException event?"
You register an event handler with the event. If a task faults and you don't observe the exception in some way (e.g. access that Task's Result, Wait on it, access its Exception property after its completed, etc.), UnobservedTaskException will be raised. If you want to then treat the exception as having been observed, you can call SetObserved() on the event args provided to the event. In .NET 4, if none of the handlers observe the exception, the exception will be propagated on the finalizer thread.
- Marked As Answer by zhangzhzh Thursday, March 01, 2012 3:35 PM
-
Thursday, March 01, 2012 3:35 PM
It will be better if you can show a simple example about the TaskScheduler.UnobservedTaskException event :)
Thanks, Stephen.
-
Thursday, March 01, 2012 4:08 PMOwner
TaskScheduler.UnobservedTaskException += (sender, eventArgs) =>
{
Console.WriteLine(eventArgs.Exception.Message); // log the exception
eventArgs.SetObserved(); // mark it as having been observed
};- Marked As Answer by zhangzhzh Tuesday, March 06, 2012 2:20 AM
-
Friday, March 02, 2012 3:12 AM
Hi, Stephen.
I'm using ASP MVC 2. The architecture of my application as below:
1. a DBAccessLayer //layer for accessing database
2. a ServiceLayer //layer to connect 1 and 3.
3. a WebLayer //Web UI layerI using TPL in each layer, my question is: where should I place the TaskScheduler.UnobservedTaskException handler?
Should I place it in the Global.asax of WebLayer as below:
public class HandleAndLogErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { base.OnException(filterContext); TaskScheduler.UnobservedTaskException += (sender, eventArgs) => { Console.WriteLine(eventArgs.Exception.Message); // log the exception eventArgs.SetObserved(); // mark it as having been observed }; } } public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); filters.Add(new HandleAndLogErrorAttribute()); } ...}
Do it as this, can the possible exceptions from layer 1-3 all be captured and logged?
If not, how to do it?
Thanks very much.

