У меня есть задача выполнить HttpWebRequest
с помощью
Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
который, очевидно, может потерпеть неудачу с WebException
. Вызывающему абоненту я хочу вернуть Task<HttpResult>
, где HttpResult
— вспомогательный тип для инкапсуляции ответа (или нет). В этом случае ответ 4xx или 5xx не является исключением.
Поэтому к задаче запроса я прикрепил два продолжения. Один с TaskContinuationOptions
OnlyOnRanToCompletion
, а другой с OnlyOnOnFaulted
. А затем завернули все это в Task<HttpResult>
, чтобы получить один результат в зависимости от того, какое продолжение завершится.
Каждая из трех дочерних задач (запрос плюс два продолжения) создается с параметром AttachedToParent
.
Но когда вызывающий объект ожидает возвращенную внешнюю задачу, выдается AggregateException
, если запрос не выполнен.
Я хочу, чтобы в продолжении с ошибкой наблюдалось WebException
, чтобы клиентский код мог просто посмотреть на результат. Добавление Wait
в броски продолжения при ошибке, но try-catch вокруг этого не помогает. Не смотрите и на свойство 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;
}
с участием:
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
будет брошено, удалены. - person Richard   schedule 19.02.2010