Ric*_*ard 5 .net-4.0 parallel-extensions
我有一个任务来执行HttpWebRequest使用
Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
Run Code Online (Sandbox Code Playgroud)
这显然可能会失败WebException.对于调用者我想返回一个Task<HttpResult>where HttpResult辅助类型来封装响应(或不是).在这种情况下,4xx或5xx响应也不例外.
因此,我在请求任务中附加了两个延续.一个与TaskContinuationOptions OnlyOnRanToCompletion另一个OnlyOnOnFaulted.然后将整个事物包裹Task<HttpResult>起来以获取一个结果,无论哪个继续完成.
使用该AttachedToParent选项创建三个子任务(请求加两个延续)中的每一个.
但是当调用者等待返回的外部任务时,AggregateException抛出的是请求失败.
我想,在故障延续中,观察WebException所以客户端代码只能查看结果.添加一个Waiton on fault continuation抛出,但是试一试这个并没有帮助.也不看Exception属性(如节"五合一例外通过使用Task.Exception属性"暗示在这里).
我可以安装一个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;
}
Run Code Online (Sandbox Code Playgroud)
有:
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;
}
Run Code Online (Sandbox Code Playgroud)
(HandleWebRequestSuccess最终会剥离进一步的任务以获得响应的内容......)
客户端应该能够等待任务,然后查看其结果,而不会由于预期和已经处理的故障而抛出.
最后我采取了我能想到的最简单的路线:隐藏异常。这是可能的,因为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;
}
});
Run Code Online (Sandbox Code Playgroud)
然后在延续任务中处理错误、重定向和成功响应。