System.Net.Http.HttpClient et System.Net.Http.HttpClientHandler dans .NET Framework 4.5 implémentent IDisposable (via System.Net.Http.HttpMessageInvoker ).
La using
documentation de la déclaration indique:
En règle générale, lorsque vous utilisez un objet IDisposable, vous devez le déclarer et l'instancier dans une instruction using.
Cette réponse utilise ce modèle:
var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("foo", "bar"),
new KeyValuePair<string, string>("baz", "bazinga"),
});
cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
var result = client.PostAsync("/test", content).Result;
result.EnsureSuccessStatusCode();
}
Mais les exemples les plus visibles de Microsoft n'appellent pas Dispose()
explicitement ou implicitement. Par exemple:
- L' article de blog original annonçant la relocalisation de HttpClient.
- La documentation MSDN réelle pour HttpClient.
- BingTranslateSample
- GoogleMapsSample
- WorldBankSample
Dans les commentaires de l' annonce , quelqu'un a demandé à l'employé de Microsoft:
Après avoir vérifié vos échantillons, j'ai vu que vous n'avez pas effectué l'action d'élimination sur l'instance HttpClient. J'ai utilisé toutes les instances de HttpClient avec l'instruction using sur mon application et j'ai pensé que c'était la bonne façon puisque HttpClient implémente l'interface IDisposable. Suis-je sur la bonne voie?
Sa réponse a été:
En général, c'est correct, bien que vous deviez faire attention à «utiliser» et asynchroniser car ils ne se mélangent pas vraiment dans .Net 4, dans .Net 4.5, vous pouvez utiliser «attendre» dans une instruction «using».
Btw, vous pouvez réutiliser le même HttpClient autant de fois que vous le souhaitez, donc généralement vous ne les créerez / supprimerez pas tout le temps.
Le deuxième paragraphe est superflu pour cette question, qui ne concerne pas le nombre de fois où vous pouvez utiliser une instance HttpClient, mais s'il est nécessaire de la supprimer une fois que vous n'en avez plus besoin.
(Mise à jour: en fait, le deuxième paragraphe est la clé de la réponse, comme indiqué ci-dessous par @DPeden.)
Mes questions sont donc:
Est-il nécessaire, compte tenu de l'implémentation actuelle (.NET Framework 4.5), d'appeler Dispose () sur les instances HttpClient et HttpClientHandler? Clarification: par "nécessaire", je veux dire s'il y a des conséquences négatives pour ne pas disposer, comme des risques de fuite de ressources ou de corruption de données.
Si ce n'est pas nécessaire, serait-ce de toute façon une "bonne pratique", puisqu'ils implémentent IDisposable?
S'il est nécessaire (ou recommandé), ce code mentionné ci-dessus le met-il en œuvre en toute sécurité (pour .NET Framework 4.5)?
Si ces classes ne nécessitent pas d'appeler Dispose (), pourquoi ont-elles été implémentées comme IDisposable?
S'ils l'exigent ou s'il s'agit d'une pratique recommandée, les exemples Microsoft sont-ils trompeurs ou dangereux?
la source
Flush
un après chaque écriture, et à part l'inconvénient de continuer à conserver les ressources sous-jacentes plus longtemps que nécessaire, que ne se produira-t-il pas qui est requis pour un "comportement correct"?Réponses:
Le consensus général est que vous n'avez pas (ne devez pas) disposer de HttpClient.
Beaucoup de gens qui sont intimement impliqués dans son fonctionnement l'ont déclaré.
Voir l'article de blog de Darrel Miller et un article SO connexe: l' exploration HttpClient entraîne une fuite de mémoire pour référence.
Je vous suggère également fortement de lire le chapitre HttpClient de Designing Evolvable Web APIs avec ASP.NET pour le contexte sur ce qui se passe sous le capot, en particulier la section "Lifecycle" citée ici:
Ou même ouvrez DotPeek.
la source
Timeout
propriété ne se piétinerait-il pas?Les réponses actuelles sont un peu confuses et trompeuses, et il leur manque certaines implications DNS importantes. Je vais essayer de résumer clairement où en sont les choses.
IDisposable
objets devraient idéalement être éliminés lorsque vous en avez terminé , en particulier ceux qui possèdent des ressources de système d'exploitation nommées / partagées .HttpClient
ne fait pas exception, car comme le souligne Darrel Miller , il alloue des jetons d'annulation, et les corps de demande / réponse peuvent être des flux non gérés.Connection:close
tête après les modifications DNS. Une autre possibilité consiste à recycler leHttpClient
côté client, soit périodiquement, soit via un mécanisme qui apprend le changement DNS. Voir https://github.com/dotnet/corefx/issues/11224 pour plus d'informations (je suggère de le lire attentivement avant d'utiliser aveuglément le code suggéré dans le billet de blog lié).la source
À ma connaissance, l'appel
Dispose()
n'est nécessaire que lorsqu'il bloque les ressources dont vous avez besoin plus tard (comme une connexion particulière). Il est toujours recommandé de libérer les ressources que vous n'utilisez plus, même si vous n'en avez plus besoin, simplement parce que vous ne devriez généralement pas conserver les ressources que vous n'utilisez pas (jeu de mots voulu).L'exemple Microsoft n'est pas incorrect, nécessairement. Toutes les ressources utilisées seront libérées à la fermeture de l'application. Et dans le cas de cet exemple, cela se produit presque immédiatement après l'
HttpClient
utilisation du. Dans des cas similaires, appeler explicitementDispose()
est quelque peu superflu.Mais, en général, lorsqu'une classe est implémentée
IDisposable
, il est entendu que vous devez vérifierDispose()
ses instances dès que vous êtes complètement prêt et capable. Je suppose que cela est particulièrement vrai dans des cas comme ceuxHttpClient
où il n'est pas explicitement documenté si les ressources ou les connexions sont conservées sur / ouvertes. Dans le cas où la connexion sera réutilisée à nouveau [bientôt], vous voudrez y renoncerDipose()
- vous n'êtes pas "entièrement prêt" dans ce cas.Voir aussi: Méthode IDisposable.Dispose et quand appeler Dispose
la source
Dispose()
prématurément et devez vous reconnecter quelques secondes plus tard si la connexion existante est réutilisable. De même, vous ne voulez pas inutilementDispose()
d'images ou d'autres structures que vous pourriez avoir à reconstruire en une minute ou deux.Dispose () appelle le code ci-dessous, qui ferme les connexions ouvertes par l'instance HttpClient. Le code a été créé en décompilant avec dotPeek.
HttpClientHandler.cs - Éliminer
Si vous n'appelez pas dispose, ServicePointManager.MaxServicePointIdleTime, qui s'exécute par une minuterie, fermera les connexions http. La valeur par défaut est 100 secondes.
ServicePointManager.cs
Si vous n'avez pas défini le temps d'inactivité sur infini, il semble prudent de ne pas appeler dispose et de laisser le temporisateur de connexion inactive démarrer et fermer les connexions pour vous, bien qu'il serait préférable pour vous d'appeler dispose dans une instruction using si vous savez que vous avez terminé avec une instance HttpClient et libérez les ressources plus rapidement.
la source
Réponse courte: Non, l'énoncé de la réponse actuellement acceptée n'est PAS exact : "Le consensus général est que vous n'avez pas (ne devez pas) disposer de HttpClient".
Réponse longue : LES DEUX déclarations suivantes sont vraies et réalisables en même temps:
IDisposable
objet est censé / recommandé d'être éliminé.Et ils NE CONFLITENT PAS NÉCESSAIREMENT. Il s'agit simplement de savoir comment organiser votre code pour réutiliser un
HttpClient
AND et le disposer correctement.Une réponse encore plus longue citée de ma autre réponse :
Ce n'est pas une coïncidence de voir des gens dans certains articles de blog blâmer la façon dont
HttpClient
l'IDisposable
interface les fait avoir tendance à utiliser leusing (var client = new HttpClient()) {...}
modèle et ensuite conduire à un problème de gestionnaire de socket épuisé.Je crois que cela revient à une conception (inexacte?) Tacite: "un objet IDisposable devrait être de courte durée" .
CEPENDANT, alors que cela ressemble certainement à une chose de courte durée lorsque nous écrivons du code dans ce style:
la documentation officielle sur IDisposable ne mentionne jamais que les
IDisposable
objets doivent être de courte durée. Par définition, IDisposable est simplement un mécanisme qui vous permet de libérer des ressources non gérées. Rien de plus. En ce sens, vous êtes censé déclencher éventuellement la cession, mais cela ne vous oblige pas à le faire de manière éphémère.Il vous appartient donc de bien choisir le moment du déclenchement de la mise au rebut, en fonction des exigences du cycle de vie de votre objet réel. Rien ne vous empêche d'utiliser un IDisposable de manière durable:
Avec cette nouvelle compréhension, maintenant nous revisitons ce billet de blog , nous pouvons clairement remarquer que le "correctif" s'initialise
HttpClient
une fois mais ne le supprime jamais, c'est pourquoi nous pouvons voir dans sa sortie netstat que, la connexion reste à l'état ESTABLISHED ce qui signifie qu'elle a PAS été correctement fermé. S'il était fermé, son état serait à la place dans TIME_WAIT. Dans la pratique, ce n'est pas grave de laisser une seule connexion ouverte après la fin de votre programme, et l'affiche du blog continue de voir un gain de performances après la correction; mais quand même, il est conceptuellement incorrect de blâmer IDisposable et de choisir de NE PAS le jeter.la source
HttpClient.Dispose
?.HttpClient client
qu'une telle suggestion semble vague, mais en fait, elle peut parfaitement s'aligner sur le cycle de vie de votre variable, ce qui est quelque chose de Programming-101 que vous faites probablement déjà de toute façon. Vous pourrez peut-être même encore l'utiliserusing (...) {...}
. Par exemple, consultez l'exemple Hello World dans ma réponse.Comme il ne semble pas que quelqu'un l'ait encore mentionné ici, la nouvelle meilleure façon de gérer HttpClient et HttpClientHandler dans .Net Core 2.1 utilise HttpClientFactory .
Il résout la plupart des problèmes et des problèmes mentionnés ci-dessus d'une manière propre et facile à utiliser. De l'excellent article de blog de Steve Gordon :
Ajoutez les packages suivants à votre projet .Net Core (2.1.1 ou version ultérieure):
Ajoutez ceci à Startup.cs:
Injecter et utiliser:
Explorez la série de publications dans le blog de Steve pour de nombreuses autres fonctionnalités.
la source
Dans mon cas, je créais un HttpClient à l'intérieur d'une méthode qui a effectivement fait l'appel de service. Quelque chose comme:
Dans un rôle de travailleur Azure, après avoir appelé à plusieurs reprises cette méthode (sans supprimer le HttpClient), elle échouerait finalement avec
SocketException
(la tentative de connexion a échoué).J'ai fait de HttpClient une variable d'instance (en la supprimant au niveau de la classe) et le problème a disparu. Donc, je dirais que oui, éliminez le HttpClient, en supposant qu'il est sûr (vous n'avez pas d'appels asynchrones en attente) pour le faire.
la source
Dans une utilisation typique (réponses <2 Go), il n'est pas nécessaire de supprimer les HttpResponseMessages.
Les types de retour des méthodes HttpClient doivent être supprimés si leur contenu de flux n'est pas entièrement lu. Sinon, le CLR n'a aucun moyen de savoir que ces flux peuvent être fermés jusqu'à ce qu'ils soient récupérés.
Si vous définissez HttpCompletionOption sur ResponseHeadersRead ou si la réponse est supérieure à 2 Go, vous devez nettoyer. Cela peut être fait en appelant Dispose sur le HttpResponseMessage ou en appelant Dispose / Close sur le flux obtenu à partir du contenu HttpResonseMessage ou en lisant le contenu complètement.
Que vous appeliez Dispose sur HttpClient dépend de si vous souhaitez annuler les demandes en attente ou non.
la source
Si vous souhaitez supprimer HttpClient, vous pouvez le faire si vous le configurez en tant que pool de ressources. Et à la fin de votre candidature, vous disposez de votre pool de ressources.
Code:
var handler = HttpClientHander.GetHttpClientHandle (new Uri ("base url")).
la source
Dispose
méthode que vous enregistrez sur GC. Cela devrait être noté plus haut sur le dessus.L'utilisation de l'injection de dépendances dans votre constructeur facilite la gestion de la durée de vie de votre
HttpClient
- en prenant la gestion de la vie en dehors du code qui en a besoin et en la rendant facilement modifiable à une date ultérieure.Ma préférence actuelle est de créer une classe client http distincte qui hérite d'
HttpClient
une fois par domaine de point de terminaison cible , puis d'en faire un singleton à l'aide de l'injection de dépendances.public class ExampleHttpClient : HttpClient { ... }
Ensuite, je prends une dépendance de constructeur sur le client http personnalisé dans les classes de service où j'ai besoin d'accéder à cette API. Cela résout le problème de la durée de vie et présente des avantages en matière de regroupement de connexions.
Vous pouvez voir un exemple fonctionnel dans la réponse associée à https://stackoverflow.com/a/50238944/3140853
la source
Veuillez lire ma réponse à une question très similaire publiée ci-dessous. Il doit être clair que vous devez traiter les
HttpClient
instances comme des singletons et réutiliser à travers les requêtes.Quelle est la surcharge de création d'un nouveau HttpClient par appel dans un client WebAPI?
la source
Je pense que l'on devrait utiliser un motif singleton pour éviter d'avoir à créer des instances de HttpClient et à le fermer tout le temps. Si vous utilisez .Net 4.0, vous pouvez utiliser un exemple de code comme ci-dessous. pour plus d'informations sur le motif singleton, cliquez ici .
Utilisez le code ci-dessous.
la source