如何在连续任务中强制执行任务中的异常?

时间:2010-02-19 12:10:12

标签: .net-4.0 parallel-extensions

我有一项任务是使用

执行HttpWebRequest
 Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)

WebException显然会失败。对于调用者,我想返回一个Task<HttpResult>,其中HttpResult是一个帮助器类型来封装响应(或不是)。在这种情况下,4xx或5xx响应异常。

因此我在请求任务中添加了两个延续。一个使用TaskContinuationOptions OnlyOnRanToCompletion,另一个使用OnlyOnOnFaulted。然后将整个事物包裹在Task<HttpResult>中以获取一个结果,无论哪个继续完成。

使用AttachedToParent选项创建三个子任务(请求加两个延续)中的每一个。

但是当调用者等待返回的外部任务时,抛出AggregateException请求失败。

我想在故障延续中观察WebException,以便客户端代码可以查看结果。在故障延续中添加Wait会引发,但是尝试捕获它并没有帮助。也没有查看Exception属性(作为“使用Task.Exception属性观察异常”一节提示here)。

我可以安装一个UnobservedTaskException事件处理程序进行过滤,但由于事件没有提供与故障任务的直接链接,这可能会在应用程序的这一部分之外进行交互,并且是一个大锤破解一个坚果的情况

鉴于出现故障Task<T>的实例,有没有办法将其标记为“处理错误”?

简化代码:

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;
}

使用:

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最终会剥离更多任务以获取响应的内容......)

客户端应该能够等待任务,然后查看其结果,而不会由于预期的错误和已经处理的错误而抛出。

1 个答案:

答案 0 :(得分:3)

最后我采取了我能想到的最简单的路线:隐藏异常。这是可能的,因为WebException有一个属性Response,可以访问我想要的HttpWebResponse

var requestTask = Task<WebResponse>.Factory.FromAsync(
                        webReq.BeginGetResponse,
                        ia => {
                          try {
                            return webReq.EndGetResponse(ia);
                          } catch (WebException exn) {
                            requestState.Log(...);
                            return exn.Response;
                          }
                        });

然后在继续任务中处理错误,重定向和成功响应。