web-dev-qa-db-fra.com

Comment puis-je savoir quand HttpClient a expiré?

Autant que je sache, il n’ya aucun moyen de savoir qu’il s’agit précisément d’un dépassement de délai. Est-ce que je ne cherche pas au bon endroit ou est-ce que je manque quelque chose de plus grand?

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);
}

Cela retourne:

Une ou plusieurs erreurs sont survenues.

Une tâche a été annulée.

116
Benjol

Vous devez attendre la méthode GetAsync. Il lancera alors un TaskCanceledException s'il a expiré. De plus, GetStringAsync et GetStreamAsync gèrent en interne le délai d'attente, afin qu'ils ne jettent JAMAIS.

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);
}
58
murkaeus

Je reproduis le même problème et c'est vraiment énervant. J'ai trouvé cela utile:

HttpClient - traitant des exceptions globales

n bogue dans HttpClient.GetAsync devrait renvoyer une exception WebException et non une exception TaskCanceledException

Quelques codes au cas où les liens ne vont nulle part:

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!?)
    }
}
53
vezenkov

J'ai constaté que le meilleur moyen de déterminer si l'appel de service avait expiré est d'utiliser un jeton d'annulation et non la propriété de délai d'attente de HttpClient:

var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);

Et puis gérer l'AnnulationException lors de l'appel de service ...

catch(TaskCanceledException)
{
    if(!cts.Token.IsCancellationRequested)
    {
        // Timed Out
    }
    else
    {
        // Cancelled for some other reason
    }
}

Bien sûr, si le délai d'attente se situe du côté du service, cela devrait pouvoir être géré par une exception WebException.

20
Jack

De http://msdn.Microsoft.com/en-us/library/system.net.http.httpclient.timeout.aspx

Une requête DNS (Domain Name System) (DNS) peut prendre jusqu'à 15 secondes pour revenir ou expirer. Si votre demande contient un nom d'hôte qui nécessite une résolution et que vous définissez Timeout sur une valeur inférieure à 15 secondes, 15 secondes ou plus peuvent s'écouler avant que une exception WebException soit générée pour indiquer un dépassement de délai sur votre demande. .

Vous aurez alors accès à la propriété Status, voir WebExceptionStatus

8
user247702

En gros, vous devez attraper le OperationCanceledException et vérifier l’état du jeton d’annulation qui a été passé à SendAsync (ou GetAsync, ou quelle que soit la méthode que vous utilisez HttpClient utilisez):

  • si elle a été annulée (IsCancellationRequested est vraie), cela signifie que la demande a vraiment été annulée
  • sinon, cela signifie que la demande a expiré

Bien sûr, ce n'est pas très pratique ... il serait préférable de recevoir un TimeoutException en cas de dépassement du délai d'attente. Je propose ici une solution basée sur un gestionnaire de messages HTTP personnalisé: Meilleure gestion du délai d’attente avec HttpClient

5
Thomas Levesque
_httpClient = new HttpClient(handler) {Timeout = TimeSpan.FromSeconds(5)};

c’est ce que je fais habituellement, semble bien marcher pour moi, c’est particulièrement bien quand on utilise des mandataires.

3
Syv Development