内部HttpClient.SendAsync
(すべてのリクエストを送信するために使用される内部メソッド) を見ると、Task
作成されているのは単純なTaskCompletionSource<HttpResponseMessage>
. 呼び出し元のメソッド内でthis.SetTaskFaulted
複数回設定されますが、常にif-else
ブロック内で設定されます。潜在的に発生する可能性があるSetTaskFaulted
のは、例外を設定すると、別の例外が発生する可能性があるということです:
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);
}
}
Dispose
タイマーは、そのメソッドから例外をスローする可能性があります。それは非常にまれだと確信していますが。
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;