HttpClient
組み込みのタイムアウト機能があり(すべて非同期であるにもかかわらず、つまり、タイムアウトはhttpリクエスト機能に直交していると見なすことができるため、一般的な非同期ユーティリティで処理できますが、それは別として)、タイムアウトが開始されると、TaskCanceledException
(ラップされたAggregateException
)。
TCEには、CancellationToken
に等しいが含まれていCancellationToken.None
ます。
今、私が自分のものを提供HttpClient
し、CancellationToken
それを使用して、操作が終了する(またはタイムアウトする)前に操作をキャンセルすると、まったく同じTaskCanceledException
、再び。を取得しCancellationToken.None
ます。
スローされた例外だけを見て、例外CancellationToken
をチェックするコードに自分自身をアクセス可能にすることなく、タイムアウトが要求をキャンセルしたかどうかを判断する方法はまだありますか?
PSこれはバグであり、CancellationToken
どういうわけか間違って修正された可能性がありCancellationToken.None
ますか?カスタムCancellationTokenを使用してキャンセルされたTaskCanceledException.CancellationToken
場合、そのカスタムトークンと同じになると思います。
編集
問題をもう少し明確にするために、オリジナルCancellationTokenSource
にアクセスして、タイムアウトとユーザーキャンセルを簡単に区別できます。
origCancellationTokenSource.IsCancellationRequested == true
ただし、例外からを取得するCancellationToken
と、間違った答えが返されます。
((TaskCanceledException)e.InnerException).CancellationToken.IsCancellationRequested == false
ここに、人気のある需要のための最小限の例があります。
public void foo()
{
makeRequest().ContinueWith(task =>
{
try
{
var result = task.Result;
// do something with the result;
}
catch (Exception e)
{
TaskCanceledException innerException = e.InnerException as TaskCanceledException;
bool timedOut = innerException != null && innerException.CancellationToken.IsCancellationRequested == false;
// Unfortunately, the above .IsCancellationRequested
// is always false, no matter if the request was
// cancelled using CancellationTaskSource.Cancel()
// or if it timed out
}
});
}
public Task<HttpResponseMessage> makeRequest()
{
var cts = new CancellationTokenSource();
HttpClient client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) };
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "url");
passCancellationTokenToOtherPartOfTheCode(cts);
return client.SendAsync(httpRequestMessage, cts.Token);
}