Nouvelle Tentative De HttpClient Demandes Infructueuses
Je fais construire une fonction qui étant donné un HttpContent Objet, sera questions de la demande et de nouvelles tentatives en cas d'échec. Cependant, je reçois des exceptions dire que HttpContent Objet est éliminé après la publication de la demande. Est-il de toute façon pour copier ou reproduire le HttpContent Objet afin que je puisse émettre des demandes multiples.
public HttpResponseMessage ExecuteWithRetry(string url, HttpContent content)
{
HttpResponseMessage result = null;
bool success = false;
do
{
using (var client = new HttpClient())
{
result = client.PostAsync(url, content).Result;
success = result.IsSuccessStatusCode;
}
}
while (!success);
return result;
}
//Works with no exception if first request is successful
ExecuteWithRetry("http://www.requestb.in/xfxcva" /*valid url*/, new StringContent("Hello World"));
//Throws if request has to be retried ...
ExecuteWithRetry("http://www.requestb.in/badurl" /*invalid url*/, new StringContent("Hello World"));
(Évidemment, je n'essayez pas indéfiniment, mais le code ci-dessus est essentiellement ce que je veux).
Il donne de cette exception
System.AggregateException: One or more errors occurred. ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Http.StringContent'.
at System.Net.Http.HttpContent.CheckDisposed()
at System.Net.Http.HttpContent.CopyToAsync(Stream stream, TransportContext context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at Submission#8.ExecuteWithRetry(String url, HttpContent content)
Est-il de toute façon pour dupliquer un HttpContent de l'Objet ou de la réutiliser?
- D'autres réponses sont bonnes pour mettre en œuvre une nouvelle tentative. Mais le vrai problème ici, c'est parce que votre HttpContent est disposé après votre post. Vous avez besoin de re-créer le StringContent avant chaque tentative. Vous n'aurez pas une ObjectDisposedException comme ceci
Vous devez vous connecter pour publier un commentaire.
Au lieu de la mise en œuvre de fonctionnalité nouvelle tentative qui enveloppe le
HttpClient
, envisager la construction de laHttpClient
avec unHttpMessageHandler
qui effectue la logique de nouvelle tentative en interne. Par exemple:SendAsync
représente un unique demande de l'opération, et donc ce n'est pas la bonne façon de mettre en œuvre un mécanisme de nouvelle tentative. Une approche externe fonctionne mieux.base.SendAsync
se débarrasser de laHttpContent
passé àclient.PostAsync
. Donc, IME, votre réponse ne fonctionne pas. (La seule raison pour laquelle je suis venu à cette réponse était pour éviter d'avoir à copier le contenu dans le but de réessayer! 🙂 )HttpClient
plus unilatéralement dispose deHttpContent
, de sorte qu'une partie du problème s'en va. Voir: github.com/dotnet/corefx/pull/19082/filesDelegatingHandler
approche peut être résolu. Voir ce commentaire pour Muhammad Rehan Saeed de Polly approche. Vous pouvez appliquer un Polly TimeoutPolicy à chaque nouvelle tentative. Polly TimeoutPolicy jette un personnaliséTimeoutRejectedException
, donc cela peut être bien distinguée de l'annulation parCancellationToken
, si c'est à des utilisateurs externes de l'annulation ou deHttpClient.Timeout
de signalisation temporisation globale.ASP.NET de Base 2.1 Réponse
ASP.NET de Base 2.1 ajout du support pour Polly directement. Ici
UnreliableEndpointCallerService
est une classe qui accepte unHttpClient
dans son constructeur. Les demandes ayant échoué va réessayer avec un algorithme de reprise, de sorte que la prochaine tentative a lieu dans un exponentiellement plus de temps après le précédent:Pensez également à la lecture de mon blog "De Manière Optimale La Configuration HttpClientFactory".
D'Autres Plates-Formes De Réponse
Cette implémentation utilise Polly à réessayer avec un algorithme de reprise, de sorte que la prochaine tentative a lieu dans un exponentiellement plus de temps après la précédente. Il a également tentatives si un
HttpRequestException
ouTaskCanceledException
est levée en raison d'un dépassement de délai. Polly est beaucoup plus facile à utiliser que la Topaze..OrResult<HttpResponseMessage>(x => x.IsSuccessStatusCode)
?retryCount
àretryAttempt
. L'ancien implique que le nombre de tentatives (qui est toujours de 5) et le dernier fait en réalité référence à l'actuelle tentative, qui va de 1 à 5 dans votre exemple.DelegatingHandler
approche avec les délais d'attente, la distinction globale de délai d'attente (dans tous les essais) à partir de délai d'attente-par-essayer. La propriété Timeout sur HttpClient,HttpClient.Timeout
, va agir comme une temporisation globale à travers toutes les tentatives combiné. D'imposer un délai d'attente-par-essayer, utiliser un Polly TimeoutPolicy enveloppé à l'intérieur du WaitAndRetry politique. En outre, de Polly TimeoutPolicy jette unTimeoutRejectedException
. Le WaitAndRetry politique doit alors gérerTimeoutRejectedException
, pasTaskCanceledException
. Ce qui distingue délai d'attente-par-essayer de les deux externes d'annulation et de toutes les tentatives d'expiration.TimeoutRejectedException
), de sorte qu'une nouvelle tentative de la politique peut distinguer que de l'utilisateur à partir d'annulation. L'approche que vous suggérer de Dennis (indépendant de la source d'annulation) est effectivement ce que l'imbrication Polly RetryPolicy avec TimeoutPolicy n', comme nous le suggérons dans le Polly + HttpClientFactory doco: github.com/App-vNext/Polly/wiki/....L'actuel réponses ne fonctionnent pas comme prévu dans tous les cas, en particulier dans le cas très commun de l'expiration du délai de demande (voir mon commentaire).
En outre, ils mettent en œuvre une très naïve réessayer stratégie autant de fois que vous voulez quelque chose d'un peu plus sophosticated, tels que l'intervalle exponentielle (qui est par défaut dans l'Azure Storage API Client).
Je suis tombé sur TOPAZE lors de la lecture d'un related post de blog (offre également une fausse interne de nouvelle tentative d'approche). Voici ce que j'ai trouvé:
Note le
requester
délégué paramètre. Il devrait pas être unHttpRequestMessage
puisque vous ne pouvez pas envoyer la même demande à plusieurs reprises. Comme pour les stratégies, qui dépend de votre cas d'utilisation. Par exemple, une erreur passagère stratégie de détection pourrait être aussi simple que:Que la nouvelle tentative de la stratégie, de la TOPAZE propose trois options:
Par exemple, voici la TOPAZE équivalent de ce que l'Azur du Client de Stockage de la Bibliothèque utilise par défaut:
Pour plus d'informations, voir http://msdn.microsoft.com/en-us/library/hh680901(v=pandp.50).aspx
MODIFIER Notez que si votre requête contient un
HttpContent
objet, vous aurez à le régénérer à chaque fois qu'qui seront vendus parHttpClient
ainsi (merci pour la capture de Alexandre Pépin). Par exemple() => httpClient.PostAsync(url, new StringContent("foo")))
.HttpRequestMessage
au lieu d'un délégué comme je le fais maintenant (qui ressemble typiquement à() => client.GetAsync(url)
) puis la première à essayer serait de travailler, mais les tentatives suivantes serait un échec, la levée d'une exception au sujet de ne pas être en mesure de réutiliser le même message de demande (je ne me souviens pas exactement exception de type et libellé)Dupliquer le StringContent n'est probablement pas la meilleure idée. Mais la simple modification pourrait résoudre le problème. Juste de modifier la fonction et de créer de la StringContent objet à l'intérieur de la boucle, quelque chose comme:
et ensuite l'appeler
j'ai presque le même problème.
HttpWebRequest des files d'attente de la bibliothèque, qui garantit la demande de livraison
Je viens de mettre à jour (voir EDIT3) mon approche pour éviter les collisions, mais j'ai encore besoin de mécanisme général pour garantir la livraison d'un message (ou la re-livraison, dans le cas où le message n'a pas été livré).
Je l'ai essayé et ont travaillé pendant l'utilisation de tests unitaires et d'intégration. Cependant, il a collé quand j'ai appelé le du RESTE de l'URL. J'ai trouvé ce post intéressant ce qui explique pourquoi il se bloque sur cette ligne.
Le correctif de ce que vous avez
.ConfigureAwait(false)
ajouté à la fin.J'ai aussi ajouté créer lié jeton partie là comme ceci.
Avec RestEase Et de la Tâche, lors de la nouvelle tentative avec httpClient réutilisés dans de nombreux appel (singleton) il frezze et de le jeter TaskCanceledException.
Pour résoudre ce blé nécessité de les Éliminer() l'échec de la réponse avant de réessayer
Ce construit au large de la accepté de répondre, mais ajoute la possibilité de passer de la quantité de tentatives, plus ajoute la possibilité d'ajouter de non-blocage des retards ou des temps d'attente à chaque demande. Il utilise également un try catch pour assurer la réessayer continue à se produire après une exception s'est produite. Et enfin, j'ai ajouté le code pour sortir de la boucle dans le cas de BadRequests, vous ne voulez pas de renvoyer le mauvais même demande à plusieurs reprises.
}
Vous référer également à la Construction d'un Transitoire de Réessayer Gestionnaire pour l' .NET HttpClient.
Visite reportez-vous à KARTHIKEYAN VIJAYAKUMAR post.