2010-02-19 5 views
5

나는 작업이 분명히 WebException와 함께 실패 할 수있는작업에서 예외를 강제로 지속 작업에서 관찰하는 방법?

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

사용하여 HttpWebRequest 수행해야합니다. 호출자에게 나는 Task<HttpResult>을 반환하고자합니다. 여기서 HttpResult은 응답을 캡슐화하기위한 도우미 유형입니다 (또는 아님). 이 경우 4xx 또는 5xx 응답은 이 아니며 예외는이 아닙니다.

따라서 요청 작업에 두 개의 연속을 첨부했습니다. 하나는 TaskContinuationOptionsOnlyOnRanToCompletion이고 다른 하나는 OnlyOnOnFaulted입니다. 그리고 나서 Task<HttpResult>에 전체 내용을 포장하여 계속 작업이 완료되는 동안 하나의 결과를 선택합니다.

AttachedToParent 옵션을 사용하여 세 개의 하위 작업 (요청과 두 개의 연속)이 만들어집니다.

그러나 발신자가 반환 된 외부 작업을 대기하면 요청이 실패한 경우 AggregateException이 발생합니다.

오류가 계속되는 경우 WebException을 관찰하여 클라이언트 코드가 결과를 볼 수 있도록하고 싶습니다. on fault continuation throw에 Wait을 추가했지만이 문제를 해결하기 위해 try-catch를 사용하면 도움이되지 않습니다. Exception 속성을 보지도 않습니다 ("Task.Exception 속성을 사용하여 예외 관찰"힌트 here 섹션 참조).

필터링 할 이벤트 핸들러를 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)

클라이언트가 있어야한다 과제를 기다리고 그 결과를보고, 예상되고 이미 처리 된 결함으로 인해 던지지 않고.

+0

'TaskScheduler.UnobservedTaskException'은 (대부분은 아닐지라도)'AggregateException'이 던져 질 장소의 대부분이 제거 되어도 발생하지 않습니다. – Richard

답변

3

결국 내가 생각할 수있는 가장 단순한 경로를 택했습니다. 예외를 숨기십시오. 리디렉션 및 연속 작업의 성공 응답,

var requestTask = Task<WebResponse>.Factory.FromAsync(
         webReq.BeginGetResponse, 
         ia => { 
          try { 
          return webReq.EndGetResponse(ia); 
          } catch (WebException exn) { 
          requestState.Log(...); 
          return exn.Response; 
          } 
         }); 

그리고 오류를 처리 : WebException 내가 원하는 HttpWebResponse에 대한 액세스를 제공하는 특성 Response을 가지고 있기 때문에이 가능합니다.