У меня есть задача выполнить 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» не намекает здесь ).
Я мог бы установить обработчик события 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
в конечном итоге раскрутит дальнейшие задачи для получения содержания ответа ...)
Клиент должен иметь возможность дождаться выполнения задачи и затем посмотреть на ее результат, не выполняя его из-за ожидаемой и уже обработанной ошибки.