У меня есть задача работать HttpWebRequest
использование
Task.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
который может, очевидно, перестать работать с a WebException
. Вызывающей стороне я хочу возвратить a Task
где HttpResult
тип помощника должен инкапсулировать ответ (или не). В этом случае 4xx или 5xx ответ не является исключением.
Поэтому я присоединил два продолжения к задаче запроса. Один с TaskContinuationOptions
OnlyOnRanToCompletion
и другой с OnlyOnOnFaulted
. И затем перенесенный все это в a Task
взять один результат, какой бы ни продолжение завершается.
Каждая из трех дочерних задач (запрос плюс два продолжения) создается с AttachedToParent
опция.
Но когда вызывающая сторона ожидает на возвращенной внешней задаче, AggregateException
брошен отказавший запрос.
Я хочу, в на неработающем продолжении, наблюдать WebException
таким образом, клиентский код может просто посмотреть на результат. Добавление a Wait
в на бросках продолжения отказа, но выгоде попытки вокруг этого не помогает. Ни делает взгляд на Exception
свойство (поскольку раздел "Observing Exceptions By Using the Task. Exception Property" подсказывает здесь).
Я мог установить a UnobservedTaskException
обработчик событий для фильтрации но поскольку событие не предлагает прямой ссылки на неработающую задачу, это будет, вероятно, взаимодействовать вне этой части приложения и является случаем кувалды для взламывания гайки.
Приведенный пример неработающего Task
есть ли какое-либо средство установки флага его как "обработанный отказ"?
Упрощенный код:
public static Task Start(Uri url) {
var webReq = BuildHttpWebRequest(url);
var result = new HttpResult();
var taskOuter = Task.Factory.StartNew(() => {
var tRequest = Task.Factory.FromAsync(
webReq.BeginGetResponse,
webReq.EndGetResponse,
null, TaskCreationOptions.AttachedToParent);
var tError = tRequest.ContinueWith(
t => HandleWebRequestError(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnFaulted);
var tSuccess = tRequest.ContinueWith(
t => HandleWebRequestSuccess(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnRanToCompletion);
return result;
});
return taskOuter;
}
с:
private static HttpDownloaderResult HandleWebRequestError(
Task 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
в конечном счете отделит дальнейшие задачи получить контент ответа...),
Клиент должен смочь ожидать на задаче и затем посмотреть на ее результат без него бросающий из-за отказа, который ожидается и уже обрабатывается.
В конце концов я выбрал самый простой путь, который мог придумать: скрыть исключение. Это возможно, потому что 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;
}
});
И затем обрабатывать ошибки, перенаправления и успешные ответы в продолжение задачи.