【问题标题】:How to Force an Exception from a Task to be Observed in a Continuation Task?如何强制在继续任务中观察任务中的异常?
【发布时间】:2010-02-19 12:10:11
【问题描述】:

我有一个任务是使用 HttpWebRequest 执行

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

这显然会因WebException 而失败。我想向调用者返回一个Task&lt;HttpResult&gt;,其中HttpResult 是封装响应(或不封装响应)的辅助类型。在这种情况下,4xx 或 5xx 响应不是例外。

因此,我在请求任务中附加了两个延续。一个是TaskContinuationOptions OnlyOnRanToCompletion,另一个是OnlyOnOnFaulted。然后将整个内容包裹在 Task&lt;HttpResult&gt; 中,以获取一个结果,无论哪一个继续完成。

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

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

我想在 on faulted continuation 中观察 WebException 以便客户端代码可以查看结果。在 on fault continuation throws 中添加 Wait,但围绕此问题的 try-catch 无济于事。也没有查看 Exception 属性(作为“使用 Task.Exception 属性观察异常”部分提示 here)。

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

给定一个故障Task&lt;T&gt; 的实例,是否有任何方法可以将其标记为“已处理故障”?

简化代码:

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 最终会衍生出更多任务来获取响应的内容...)

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

【问题讨论】:

  • TaskScheduler.UnobservedTaskException 没有被解雇,即使大部分(如果不是全部)AggregateException 的位置将被删除。

标签: .net-4.0 parallel-extensions


【解决方案1】:

最后我采取了我能想到的最简单的方法:隐藏异常。这是可能的,因为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;
                          }
                        });

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-01
    • 2016-11-25
    • 2013-11-26
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多