, 당신이 작성중인 Task
간단한 TaskCompletionSource<HttpResponseMessage>
것을 볼 수 있습니다. 호출 메서드 내에서 this.SetTaskFaulted
을 여러 번 설정하지만 항상 if-else
블록 안에 설정합니다.
private void SetTaskFaulted(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, TaskCompletionSource<HttpResponseMessage> tcs, Exception e, TimerThread.Timer timeoutTimer)
{
this.LogSendError(request, cancellationTokenSource, "SendAsync", e);
tcs.TrySetException(e);
HttpClient.DisposeCancellationTokenAndTimer(cancellationTokenSource, timeoutTimer);
}
DisposeCancellationTokenAndTimer
내부적으로
CancellationToken
을 처분하고
finally
블록 내부의 타이머 처분 :
private static void DisposeCancellationTokenAndTimer(CancellationTokenSource cancellationTokenSource, TimerThread.Timer timeoutTimer)
{
try
{
cancellationTokenSource.Dispose();
}
catch (ObjectDisposedException)
{
}
finally
{
HttpClient.DisposeTimer(timeoutTimer);
}
}
무엇 잠재적으로 일어날 수있는 것은 SetTaskFaulted
예외를 설정할 때, 또 다른 예외를 설정할 수 있다는 것입니다 타이머가 잠재적으로 Dispose
메서드에서 예외를 throw 할 수 있습니다. 매우 드물 긴하지만 확신합니다.
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
this.CheckDisposed();
HttpClient.CheckRequestMessage(request);
this.SetOperationStarted();
this.PrepareRequestMessage(request);
CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.pendingRequestsCts.Token);
TimerThread.Timer timeoutTimer = this.SetTimeout(linkedCts);
TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();
try
{
base.SendAsync(request, linkedCts.Token).ContinueWithStandard(delegate(Task<HttpResponseMessage> task)
{
try
{
this.DisposeRequestContent(request);
if (task.IsFaulted)
{
this.SetTaskFaulted(request, linkedCts, tcs, task.Exception.GetBaseException(), timeoutTimer);
}
else
{
if (task.IsCanceled)
{
this.SetTaskCanceled(request, linkedCts, tcs, timeoutTimer);
}
else
{
HttpResponseMessage result = task.Result;
if (result == null)
{
this.SetTaskFaulted(request, linkedCts, tcs, new InvalidOperationException(SR.net_http_handler_noresponse), timeoutTimer);
}
else
{
if (result.Content == null || completionOption == HttpCompletionOption.ResponseHeadersRead)
{
this.SetTaskCompleted(request, linkedCts, tcs, result, timeoutTimer);
}
else
{
this.StartContentBuffering(request, linkedCts, tcs, result, timeoutTimer);
}
}
}
}
}
catch (Exception ex)
{
if (Logging.On)
{
Logging.Exception(Logging.Http, this, "SendAsync", ex);
}
tcs.TrySetException(ex);
}
});
}
catch
{
HttpClient.DisposeTimer(timeoutTimer);
throw;
}
return tcs.Task;
'작업'이 반환되고 하나 이상의 예외를 캡슐화 할 수 있기 때문에 'AggregationException'이 발생합니다. 이러한 비동기 메소드에 대해'await'하면 코드 내에 하나 이상의 예외가 발생했는지를 추측하지 않아도됩니다. –
죄송합니다. 명확하지 않은 경우 왜 던져 졌는지 그리고 처리하는 방법을 알고 있습니다. 나는 위의 시나리오에 대한 예를 든 사람이 있는지 알고 싶었습니다. 개인적으로 만들 수 없기 때문에 교육 목적으로 만 필요합니다. – Mayoweezy
하나의 예외를 던지는 것에 의존하지 않겠습니다. 아마도 일반적인 유스 케이스 일 것이지만, 항상 놀랄 수 있습니다. 교육 목적을위한 것이라면 아마도 대부분의 경우 * 단 하나의 예외가 발생하지만 결코 그것에 의존해서는 안된다고 말하는 것이 합리적 일 것입니다. 그들은'AggregationException.Flatten' (내부 예외가'AggregationException' 유형이었던 경우)을 호출 할 수 있고 주어진 enumerable을 반복 할 수 있습니다. –