How to Force an Exception from a Task to be Observed in a Continuation Task?
Posted
by Richard
on Stack Overflow
See other posts from Stack Overflow
or by Richard
Published on 2010-02-19T12:10:11Z
Indexed on
2010/04/19
13:13 UTC
Read the original article
Hit count: 306
parallel-extensions
|.net-4.0
I have a task to perform an HttpWebRequest
using
Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
which can obviously fail with a WebException
. To the caller I want to return a Task<HttpResult>
where HttpResult
is a helper type to encapsulate the response (or not). In this case a 4xx or 5xx response is not an exception.
Therefore I've attached two continuations to the request task. One with TaskContinuationOptions
OnlyOnRanToCompletion
and the other with OnlyOnOnFaulted
. And then wrapped the whole thing in a Task<HttpResult>
to pick up the one result whichever continuation completes.
Each of the three child tasks (request plus two continuations) is created with the AttachedToParent
option.
But when the caller waits on the returned outer task, an AggregateException
is thrown is the request failed.
I want to, in the on faulted continuation, observe the WebException
so the client code can just look at the result. Adding a Wait
in the on fault continuation throws, but a try-catch around this doesn't help. Nor does looking at the Exception
property (as section "Observing Exceptions By Using the Task.Exception Property" hints here).
I could install a UnobservedTaskException
event handler to filter, but as the event offers no direct link to the faulted task this will likely interact outside this part of the application and is a case of a sledgehammer to crack a nut.
Given an instance of a faulted Task<T>
is there any means of flagging it as "fault handled"?
Simplified code:
public static Task<HttpResult> Start(Uri url) {
var webReq = BuildHttpWebRequest(url);
var result = new HttpResult();
var taskOuter = Task<HttpResult>.Factory.StartNew(() => {
var tRequest = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
webReq.EndGetResponse,
null, TaskCreationOptions.AttachedToParent);
var tError = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestError(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnFaulted);
var tSuccess = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestSuccess(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnRanToCompletion);
return result;
});
return taskOuter;
}
with:
private static HttpDownloaderResult HandleWebRequestError(
Task<WebResponse> respTask,
HttpResult result) {
Debug.Assert(respTask.Status == TaskStatus.Faulted);
Debug.Assert(respTask.Exception.InnerException is WebException);
// Try and observe the fault: Doesn't help.
try {
respTask.Wait();
} catch (AggregateException e) {
Log("HandleWebRequestError: waiting on antecedent task threw inner: "
+ e.InnerException.Message);
}
// ... populate result with details of the failure for the client ...
return result;
}
(HandleWebRequestSuccess
will eventually spin off further tasks to get the content of the response...)
The client should be able to wait on the task and then look at its result, without it throwing due to a fault that is expected and already handled.
© Stack Overflow or respective owner