Singleton httpclient vs la création de nouveaux httpclient demande
Je suis en train de créer une couche de service web à l'aide de HttpClient dans mon Xamarin.Forms
application mobile.
- sans singlton modèle
- avec le pattern singleton
dans première approche, je suis la création de nouveaux client http objet dans chaque nouvelle demande
par application mobile.
voici mon code
public HttpClient GetConnection()
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(baseAddress);
httpClient.Timeout = System.TimeSpan.FromMilliseconds(timeout);
return httpClient;
}
post de demande de code
public async Task<TResult> PostAsync<TRequest, TResult>(String url, TRequest requestData)
{
HttpClient client = GetConnection();
String responseData = null;
if (client != null)
{
String serializedObject = await Task.Run(() => JsonConvert.SerializeObject(requestData, _jsonSerializerSettings));
var jsonContent = new StringContent(serializedObject, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(new Uri(url, UriKind.Relative), jsonContent);
responseData = await HandleResponse(response);
return await Task.Run(() => JsonConvert.DeserializeObject<TResult>(responseData, _jsonSerializerSettings));
}
else
{
throw new NullReferenceException("NullReferenceException @ PostAsync httpclient is null WebRequest.cs");
}
}
client utilise le code suivant pour l'exécution de la demande
new LoginService(new WebRequest()).UserLogin(userRequest);
à l'intérieur de la classe qui implémente IWebRequest
_webRequest.PostAsync<UserRequest,bool>(Constants.USER_LOGIN, userRequest);
dans deuxième approche, je suis en réutilisant les mêmes http objet client à chaque nouvelle demande
ici , ma classe singleton est thread-safe trop.
private static readonly Lazy<HttpService> lazy =
new Lazy<HttpService>(() => new HttpService());
public static HttpService Instance { get { return lazy.Value; } }
private HttpClient getConnection()
{
client = new HttpClient();
client.Timeout = System.TimeSpan.FromMilliseconds(timeout);
//client.MaxResponseContentBufferSize = 500000;
client.BaseAddress = new Uri(baseAddress);
return client;
}
post de demande de code
public Task<HttpResponseMessage> sendData(String url,String jsonData)
{
var jsonContent = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
return getConnection().PostAsync(new Uri(url, UriKind.Relative), jsonContent);
}
client utilise le code suivant pour exécuter
HttpService.Instance.sendData(...)
je suis passé par de nombreuses bibliothèques comme RestSharp
sur le web juste pour explorer le meilleur et j'ai trouvé que la plupart d'entre eux sont en train de créer de nouveaux objets par demande. donc, je ne sais pas quel modèle vous convient le mieux.
- Ne crée pas de
HttpClient
, et pourquoi. - HttpClient implémente IDisposable, qui doivent être satisfaites (sauf si vous utilisez une instance statique de celui-ci)
Vous devez vous connecter pour publier un commentaire.
Mise à jour: Il semble que l'utilisation d'une seule instance statique de
HttpClient
ne respecte pas les modifications de DNS, donc la solution est d'utiliserHttpClientFactory
. Voir ici pour Microsoft docs à ce sujet.D'utiliser le
HttpClientFactory
vous devez utiliser Microsoft de l'injection de dépendance. C'est la valeur par défaut pour ASP.NET les grands projets, mais pour les autres, vous devrez référence Microsoft.Extensions.Http et Microsoft.Extensions.DependencyInjection.Ensuite, lorsque vous créez votre conteneur de service, il vous suffit d'appeler
AddHttpClient()
:Et puis vous pouvez injecter
HttpClient
dans vos services, et derrière les coulissesHttpClientFactory
permettra de maintenir un pool deHttpClientHandler
objets de maintien de votre DNS frais et la prévention des problèmes avec le pool de connexion de l'épuisement.Vieille réponse:
Singleton est la façon correcte d'utiliser
HttpClient
. Veuillez voir cette l'article pour plus de détails.Microsoft docs état:
Et en effet, nous avons constaté dans notre application. Nous avons un code qui peut potentiellement faire des centaines de requêtes à l'API dans un
foreach
boucle, et pour chaque itération, nous avons été la création d'unHttpClient
enveloppé dans unusing
. Bientôt, nous avons commencé à recevoir des harengs rouges erreurs de notreMongoClient
disant qu'il avait expiré en essayant de se connecter à la base de données. Après la lecture de l'article lié, nous avons constaté que, même après l'élimination deHttpClient
, et réalisé que nous étions en épuisant les prises disponibles.La seule chose à noter est que des choses comme
DefaultRequestHeaders
etBaseAddress
sera appliquée n'importe où que HttpClient est utilisé. Comme un singleton, c'est potentiellement tout au long de l'application. Vous pouvez toujours créer plusieursHttpClient
des instances de votre application, mais juste être conscient que chaque fois que vous le faites, ils créent un nouveau pool de connexions et, comme tel, doit être créé avec parcimonie.Comme l'a souligné hvaughan3, vous ne pouvez pas modifier l'instance de
HttpMessageHandler
utilisé par le client http, donc si c'est important pour vous, vous devez utiliser une instance séparée avec ce gestionnaire.HttpClient
exemple pour chaque.IWebRequest
interface que j'ai utilisé dans ma première approche d'invoquerPostAsync
en faisantWebRequest
classe singletonSendAsyc
et ensuite construire leHttpRequestMessage
moi-même. Notez que vous n'avez pas besoin de faire de votre classe WebRequest un singleton, vous pouvez simplement faire HttpClient un singleton.BaseAddress
s'appliquerait à tous lesHttpClient
demandes. Si vous ne voulez pas que cela soit le cas, vous devrez vous déplacer dansWebRequest
manuellement et de le combiner avec l'URL relative.GetConnection()
devrait toujours revenir à la même instance.WebRequest.HttpInstance.BaseAddress = new Uri(GetBaseAddress());
en passant par leGetBaseAddress
fonction de uriWebRequest
new HttpClient()
🙂HttpClient
créé parclientFactory.CreateClient()
?Tout
HttpClient
est censé être réutilisé, il ne signifie pas nécessairement que nous devons utiliser un singleton pour organiser notre code. Veuillez vous référer à ma réponse ici. Également cité ci-dessous.Je suis en retard à la fête, mais c'est mon parcours d'apprentissage sur ce sujet délicat.
1. Où peut-on trouver officiel de l'avocat sur la réutilisation de HttpClient?
Je veux dire, si la réutilisation HttpClient est prévu
et cela est important,
cet avocat est mieux documentée dans sa propre documentation de l'API,
plutôt que d'être caché dans beaucoup de Sujets Avancés", "la Performance (anti)modèle"
ou d'autres messages de blog là-bas.
Sinon, comment un nouvel apprenant censé le savoir avant qu'il ne soit trop tard?
Dès maintenant (Mai 2018), le premier résultat de recherche lorsque vous tapez "c# httpclient"
points à cette référence de l'API de page sur le site MSDN, qui ne mentionne pas que l'intention de tous.
Eh bien, leçon 1 ici pour les débutants est,
cliquez toujours sur le "Autres Versions" lien juste après l'aide de MSDN page de titre,
vous aurez probablement de trouver des liens vers la version actuelle de là.
Dans ce HttpClient cas, il vous amènera à la dernière document
ici contenant que l'intention description.
Je soupçonne que beaucoup de développeurs qui était nouveau à ce sujet
n'a pas trouvé la bonne page de documentation soit,
c'est pourquoi cette connaissance n'est pas largement répandue,
et les gens ont été surpris quand ils ont trouvé
plus tard,
éventuellement dans une voie difficile.
2. La (mauvaise?)conception de
using
IDisposable
Celui-ci est légèrement hors-sujet, mais encore la peine de signaler qu'il n'est pas un hasard de voir des gens
dans ces messages de blog de blâmer comment
HttpClient
'sIDisposable
interfaceles fait ont tendance à utiliser le
using (var client = new HttpClient()) {...}
modèleet puis conduire à ce problème.
Je crois que c'est un non-dits (sig?)conception:
"un IDisposable objet devrait être de courte durée".
TOUTEFOIS, bien qu'il ressemble certainement une courte durée chose quand nous écrire du code dans ce style:
la la documentation officielle sur IDisposable
ne mentionne jamais
IDisposable
objets doivent être de courte durée.Par définition, IDisposable est simplement un mécanisme pour vous permettre de vous libérer des ressources non managées.
Rien de plus. En ce sens, vous êtes ATTENDUS pour éventuellement déclencher la disposition,
mais il ne vous oblige pas à le faire dans une courte durée de la mode.
Il est donc de votre travail pour bien choisir quand déclencher l'élimination,
la base de votre objet réel du cycle de vie de l'obligation.
Il n'y a rien qui vous empêche d'utiliser un IDisposable dans une longue durée de vie moyen:
Avec cette nouvelle compréhension, maintenant nous revoir ce billet de blog,
nous pouvons clairement remarquer que la "solution" initialise
HttpClient
une fois, mais jamais en disposer,c'est pourquoi nous pouvons voir à partir de son netstat sortie,
la connexion reste à l'état ce qui signifie qu'il n'a PAS été correctement fermé.
Si c'était fermé, son état serait en TIME_WAIT à la place.
Dans la pratique, il n'est pas une grosse affaire de la fuite d'une connexion ouverte après l'ensemble de votre programme se termine,
et le blog affiche encore un gain de performance après le correctif;
mais encore, il est conceptuellement erroné de blâmer IDisposable et choisissez de ne PAS la jeter.
3. Devons-nous mettre HttpClient dans une propriété statique, ou même le mettre comme un singleton?
Basée sur la compréhension de la section précédente,
Je pense que la réponse est claire: "pas nécessairement".
Cela dépend vraiment de la façon dont vous organisez votre code,
aussi longtemps que vous réutilisez un HttpClient ET (idéalement) de la jeter par la suite.
Hilarante, pas même l'exemple dans la
Les remarques de la section de l'actuel document officiel
est-il strictement à droite. Il définit un "GoodController" de la classe,
contenant un statique HttpClient des biens qui ne seront pas éliminés;
qui désobéit à ce que un autre exemple, dans les Exemples de la section
met l'accent sur: "la nécessité de disposer d'appel ... donc application ne permet pas de fuite de ressources".
Et enfin, singleton n'est pas sans défis.
-- Cité à partir de ce discours inspirant, "L'État Global et les Singletons"
PS: SqlConnection
Celui-ci est dénuée de pertinence pour la Q&A, mais c'est probablement une bonne à savoir.
SqlConnection modèle d'utilisation est différente.
Vous n'avez PAS besoin de réutiliser SqlConnection,
parce qu'il va gérer son pool de connexions mieux de cette façon.
La différence est causée par leur approche de mise en œuvre.
Chaque HttpClient exemple utilise son propre pool de connexion (cité de
ici);
mais SqlConnection lui-même est géré par une centrale de pool de connexion,
selon cette.
Et vous avez encore le besoin de disposer de SqlConnection, même que vous êtes censé faire pour HttpClient.
Comme d'autres l'ont mentionné, la plupart
HttpClient
doit être utilisé en tant que singleton, mais il y a une exception - vous ne devez pas utiliserHttpClient
en tant que singleton lorsque vous utilisezHTTP long polling
technique, parce que vous allez bloquer d'autres demandes d'exécution.Pour le temps d'interrogation demandes, vous devriez créer des
HttpClient
.