Come posso sapere quando HttpClient è scaduto?

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):

  • se è stato cancellato ( IsCancellationRequested è vero), significa che la richiesta è stata effettivamente annullata
  • in caso contrario, significa che la richiesta è scaduta

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.