Per quanto posso dire, non c‘è modo di sapere che è specificamente un timeout che si è verificato. Non sto guardando nel posto giusto, o mi manca qualcosa di più grande?
string baseAddress = "http://localhost:8080/"; var client = new HttpClient() { BaseAddress = new Uri(baseAddress), Timeout = TimeSpan.FromMilliseconds(1) }; try { var s = client.GetAsync("").Result; } catch(Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.InnerException.Message); }
Questo restituisce:
Si sono verificati uno o più errori.
Un’attività è stata annullata.
È necessario attendere il metodo GetAsync
. Verrà quindi TaskCanceledException
una TaskCanceledException
caso di timeout. Inoltre, GetStringAsync
e GetStreamAsync
gestiscono internamente il timeout, quindi non lo faranno mai.
string baseAddress = "http://localhost:8080/"; var client = new HttpClient() { BaseAddress = new Uri(baseAddress), Timeout = TimeSpan.FromMilliseconds(1) }; try { var s = await client.GetAsync(); } catch(Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.InnerException.Message); }
Sto riproducendo lo stesso problema ed è davvero fastidioso. Ho trovato questi utili:
HttpClient: gestione di eccezioni aggregate
Bug in HttpClient.GetAsync dovrebbe generare WebException, non TaskCanceledException
Qualche codice nel caso in cui i collegamenti non andassero da nessuna parte:
var c = new HttpClient(); c.Timeout = TimeSpan.FromMilliseconds(10); var cts = new CancellationTokenSource(); try { var x = await c.GetAsync("http://linqpad.net", cts.Token); } catch(WebException ex) { // handle web exception } catch(TaskCanceledException ex) { if(ex.CancellationToken == cts.Token) { // a real cancellation, triggered by the caller } else { // a web request timeout (possibly other things!?) } }
Ho trovato che il modo migliore per determinare se la chiamata di servizio è scaduta è utilizzare un token di cancellazione e non la proprietà di timeout di HttpClient:
var cts = new CancellationTokenSource(); cts.CancelAfter(timeout);
E poi gestisci l’eccezioneExecution durante la chiamata di servizio …
catch(TaskCanceledException) { if(!cts.Token.IsCancellationRequested) { // Timed Out } else { // Cancelled for some other reason } }
Ovviamente se il timeout si verifica sul lato del servizio delle cose, dovrebbe essere gestito da una WebException.
Da http://msdn.microsoft.com/en-us/library/system.net.http.httpclient.timeout.aspx
Una query DNS (Domain Name System) può richiedere fino a 15 secondi per la restituzione o il timeout. Se la richiesta contiene un nome host che richiede una risoluzione e si imposta Timeout su un valore inferiore a 15 secondi, potrebbero essere necessari almeno 15 secondi prima che venga lanciata una WebException per indicare un timeout sulla richiesta .
Si ottiene quindi l’accesso alla proprietà Status
, vedere WebExceptionStatus
Fondamentalmente, devi prendere OperationCanceledException
e controllare lo stato del token di cancellazione passato a SendAsync
(o GetAsync
o qualsiasi HttpClient
metodo HttpClient
che stai usando):
IsCancellationRequested
è vero), significa che la richiesta è stata effettivamente annullata Naturalmente, questo non è molto conveniente … sarebbe meglio ricevere un TimeoutException
in caso di timeout. Propongo qui una soluzione basata su un gestore di messaggi HTTP personalizzato: Migliore gestione del timeout con HttpClient
_httpClient = new HttpClient(handler) {Timeout = TimeSpan.FromSeconds(5)};
è quello che faccio di solito, sembra funzionare abbastanza bene per me, è particolarmente buono quando si utilizzano i proxy.