Je suis en retard à la fête, mais voici mon parcours d’apprentissage sur ce sujet épineux.
1. Où pouvons-nous trouver le défenseur officiel de la réutilisation de HttpClient?
Je veux dire, si la réutilisation de HttpClient est prévue
et qu'il est important de le faire , un tel avocat est mieux documenté dans sa propre documentation d'API, plutôt que d'être caché dans de nombreux "Sujets avancés", "Performances (anti) modèles" ou autres blogs. . Sinon, comment un nouvel apprenant est-il censé le savoir avant qu'il ne soit trop tard?
Dès à présent (mai 2018), le premier résultat de recherche lorsque Google "c # httpclient" pointe vers cette page de référence d'API sur MSDN , ce qui ne mentionne absolument pas cette intention. Pour les débutants, la première leçon est de toujours cliquer sur le lien "Autres versions" juste après le titre de la page d’aide de MSDN. Vous y trouverez probablement des liens vers la "version actuelle". Dans ce cas HttpClient, cela vous mènera au dernier document
contenant cette description d'intention .
J'imagine que de nombreux développeurs novices dans ce sujet n'ont pas trouvé la bonne page de documentation. C'est pourquoi ces connaissances ne sont pas très répandues et les gens ont été surpris d'apprendre
plus tard , peut-être de manière difficile .
2. La (mis?) Conception de using
IDisposable
Celui-ci est un peu hors sujet, mais mérite néanmoins d'être souligné, ce n'est pas un hasard si les personnes dans les articles de blog susmentionnés blâment comment HttpClient
leur IDisposable
interface les incite à utiliser le using (var client = new HttpClient()) {...}
modèle, puis à conduire au problème.
Je crois que cela revient à une conception non dite (mal?):
"Un objet identifiable devrait être de courte durée" .
CEPENDANT, même si cela ressemble certainement à une chose de courte durée lorsque nous écrivons du code dans ce style:
using (var foo = new SomeDisposableObject())
{
...
}
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 vous permettant de libérer des ressources non gérées. Rien de plus. En ce sens, vous êtes censé éventuellement déclencher la cession, mais cela ne vous oblige pas à le faire de manière éphémère.
Il est donc de votre devoir de bien choisir quand déclencher la mise au rebut, en vous basant sur les exigences du cycle de vie de votre objet réel. Rien ne vous empêche d’utiliser un IDisposable de manière durable:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Avec cette nouvelle compréhension, maintenant nous revisitons cet article 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 PAS été correctement fermé. S'il était fermé, son état serait plutôt dans TIME_WAIT. Dans la pratique, il n’est pas difficile de laisser filtrer une seule connexion ouverte après la fin de votre programme et l’affiche du blog continue d’obtenir un gain de performances après le correctif; mais toujours, il est conceptuellement incorrect de blâmer IDisposable et de choisir de ne PAS le jeter.
3. Devons-nous mettre HttpClient dans une propriété statique, ou même le mettre comme singleton?
Sur la base de la compréhension de la section précédente, je pense que la réponse devient claire: "pas nécessairement". Cela dépend vraiment de la manière dont vous organisez votre code, tant que vous réutilisez un HttpClient ET (idéalement) le supprimez éventuellement.
De manière hilarante, même l'exemple de la
section Remarques du document officiel actuel
ne le fait pas parfaitement. Il définit une classe "GoodController", contenant une propriété statique HttpClient qui ne sera pas supprimée. qui désobéit à ce qu'un autre exemple de la section Exemples
souligne: "il faut appeler Dispose ... pour que l'application ne fuit pas de ressources".
Enfin, singleton n’est pas sans défis.
"Combien de personnes pensent que la variable globale est une bonne idée? Personne.
Combien de personnes pensent que singleton est une bonne idée? Quelques.
Ce qui donne? Les singletons ne sont qu'un groupe de variables globales. "
- Cité de cette conférence inspirante, "Global State and Singletons"
PS: SqlConnection
Celui-ci est sans rapport avec l'actuel Q & A, mais c'est probablement un bon à savoir. Le modèle d'utilisation de SqlConnection est différent. Vous n'avez PAS besoin de réutiliser SqlConnection , car il gérera mieux son pool de connexions.
La différence est causée par leur approche de mise en œuvre. Chaque instance HttpClient utilise son propre pool de connexions (cité ci-
dessous ); mais SqlConnection lui-même est géré par un pool de connexion central, selon cela .
Et vous devez toujours disposer de SqlConnection, comme vous êtes supposé le faire pour HttpClient.