HttpClient
ma wbudowaną funkcję limitu czasu (mimo że wszystkie są asynchroniczne, tj. Limity czasu mogą być traktowane jako ortogonalne w stosunku do funkcji żądania http, a zatem obsługiwane przez ogólne asynchroniczne narzędzia, ale na bok) i gdy upłynie limit czasu oczekiwania , rzuci TaskCanceledException
(owinięty w AggregateException
).Rozróżnienie limitu czasu od anulowania przez użytkownika
TCE zawiera CancellationToken
, który jest równy CancellationToken.None
.
Teraz gdybym zapewnić HttpClient
z CancellationToken
z własną rękę i używać, aby anulować operację przed jej zakończeniem (lub limit czasu), mam dokładnie to samo TaskCanceledException
znowu z CancellationToken.None
.
Czy nadal istnieje sposób, patrząc tylko na wyjątek rzucony, aby dowiedzieć się, czy limit czasu anulowania żądania, bez konieczności zrobić własny CancellationToken
dostęp do kodu, który sprawdza wyjątek?
P.S. Czy to może być błąd, a CancellationToken
został nieprawidłowo naprawiony na CancellationToken.None
? W przypadku anulowanej przy użyciu niestandardowego przypadku CancellationToken, oczekiwałbym, że TaskCanceledException.CancellationToken
będzie taki sam, jak token niestandardowy.
Edit Aby ten problem nieco bardziej jasne, z dostępem do pierwotnego CancellationTokenSource
, to jest łatwe do odróżnienia limitu czasu i obsługi rezerwacji:
origCancellationTokenSource.IsCancellationRequested == prawdziwą
Otrzymanie CancellationToken
z wyjątku, ale daje błędną odpowiedź:
((TaskCanceledException) e.InnerException) .CancellationToken.IsCancellationRequested == fałszywy
Tutaj minimalny przykład, z uwagi na duże zainteresowanie:
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);
}
proszę umieszczać minimalny fragment kodu, który wykazuje takie zachowanie. –
dlaczego kod nie uruchamia zadania obsługującego wyjątek?Ten fragment kodu powinien już mieć Token Anulowania, może zarządzać tym scenariuszem, a następnie po prostu wyrzucić wyjątek, który ma otrzymać blok próbny/catch wyższego poziomu, bez TokenSource –
@FranciscoNoriega Czasami chcesz oddzielić kod, np. aby był możliwy do ponownego użycia, a także w asynchronicznie wykonanym kodzie. W efekcie wychwytywanie wyjątków odbywa się w różnych miejscach, niż tam, gdzie został zdefiniowany kod. Nie chcę przechodzić przez cały stan, który jest zaangażowany, zwłaszcza, że wyjątek zdaje się zapewniać ten stan, kiedy jest potrzebny - z tym wyjątkiem, że nie działa tak, jak sądzę, że powinien. Rzuć okiem na przykład, który z grubsza pokazuje, jak go używam. –