web-dev-qa-db-fra.com

Singleton httpclient vs création d'une nouvelle requête httpclient

J'essaie de créer une couche pour le service Web à l'aide de HttpClient dans mon application mobile Xamarin.Forms.

  1. sans motif singlton
  2. avec motif singleton

dans premier approche, je crée un nouvel objet client http dans chaque nouvelle demande faite 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;

        }

poste demande 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");

            }

        }

le client utilisera le code suivant pour exécuter la demande

new LoginService(new WebRequest()).UserLogin(userRequest);

dans la classe qui implémente IWebRequest

_webRequest.PostAsync<UserRequest,bool>(Constants.USER_LOGIN, userRequest);

in second approche Je réutilise le même objet client http dans chaque nouvelle requêtehere, ma classe singleton est thread-safe aussi.

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

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

le client utilisera le code suivant pour exécuter 

HttpService.Instance.sendData(...)

j'ai parcouru de nombreuses bibliothèques telles que RestSharp sur le Web uniquement pour explorer le meilleur et j'ai constaté que la plupart d'entre elles créent de nouveaux objets à la demande. je ne comprends donc pas quel modèle convient le mieux.

11
Hunt

Update: Il semble que l'utilisation d'une seule instance statique de HttpClient ne respecte pas les modifications DNS. La solution consiste donc à utiliser HttpClientFactory. Voir ici pour Microsoft docs à ce sujet.


Singleton est la manière correcte d’utiliser HttpClient. S'il vous plaît voir this article pour plus de détails.

Microsoft docs state:

HttpClient est destiné à être instancié une fois et réutilisé tout au long de la vie d'une application. L'instanciation d'une classe HttpClient pour chaque requête épuise le nombre de sockets disponibles sous des charges lourdes. Cela entraînera des erreurs SocketException. Vous trouverez ci-dessous un exemple d'utilisation correcte de HttpClient.

Et en effet, nous avons trouvé cela dans notre application. Nous avons du code qui peut potentiellement faire des centaines de demandes d'API dans une boucle foreach, et pour chaque itération, nous avons créé une HttpClient encapsulée dans une using. Nous avons rapidement commencé à avoir des erreurs de hareng rouge de notre MongoClient en disant que le délai imparti à sa connexion à la base de données avait expiré. Après avoir lu l'article lié, nous avons constaté que même après avoir disposé de HttpClient, nous avons réalisé que nous épuisions les sockets disponibles. 

La seule chose à noter est que des éléments tels que DefaultRequestHeaders et BaseAddress seront appliqués partout où HttpClient est utilisé. En tant que singleton, c'est potentiellement tout au long de l'application. Vous pouvez toujours créer plusieurs instances HttpClient dans votre application, mais sachez que chaque fois que vous le faites, elles créent un nouveau pool de connexions et doivent donc être créées avec parcimonie.

Comme l'a souligné hvaughan3, vous ne pouvez pas non plus modifier l'instance de HttpMessageHandler utilisée par HttpClient. Par conséquent, si cela vous concerne, vous devez utiliser une instance distincte avec ce gestionnaire.

20
John

Bien que HttpClient soit censé être réutilisé, cela ne signifie pas nécessairement que nous devons utiliser singleton pour organiser notre code. Veuillez vous référer à ma réponse ici .

PS: Je ne sais pas si je suis censé copier et coller cette réponse ici. Faites le moi savoir.

0
RayLuo

Comme d'autres l'ont mentionné, HttpClient devrait être utilisé principalement en tant que singleton, à une exception près: vous ne devez pas utiliser HttpClient en tant que singleton lorsque vous utilisez la technique HTTP long polling, car vous bloquerez l'exécution d'autres requêtes.

Pour les demandes d'interrogation longues, vous devez créer une variable HttpClient séparée.

0
mkul