Skip to main content

Best practices for using HttpClient in c#

Introduction HttpClient is the library to Get, Post, Put,.. and call WebAPIs and it is very important to use it correctly. This Library has some methods to call web apis which all of them are Async. It is really important to use them in async method but if you are using an Async method in a console application that does not have separate UI thread you can use it like the following code : public void MySyncMethod() { using (HttpClient client = new HttpClient()) { client.BaseAddress = new Uri( "https://google.com" ); var response = client.GetAsync( "SomeAddress" ) .ConfigureAwait( false ).GetAwaiter().GetResult(); if ( response .IsSuccessStatusCode) { //Do Something... } } } Using ConfigureAwait(false) is very important for the applications which does not have separate UI thread Creating HttpClient for each request is not a good Idea and  Reuse  Httpclient as much as possible

Best practices for using HttpClient in c#

Introduction

HttpClient is the library to Get, Post, Put,.. and call WebAPIs and it is very important to use it correctly.
This Library has some methods to call web apis which all of them are Async. It is really important to use them in async method but if you are using an Async method in a console application that does not have separate UI thread you can use it like the following code :


public void MySyncMethod()
{
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri("https://google.com");
        var response = client.GetAsync("SomeAddress").ConfigureAwait(false).GetAwaiter().GetResult();
        if (response.IsSuccessStatusCode)
        {
            //Do Something...   
        }
    }
}
Using ConfigureAwait(false) is very important for the applications 
which does not have separate UI thread

Creating HttpClient for each request is not a good Idea and Reuse Httpclient as much as possible.  But you need to do it for calling deferent urls. So what we have to do ?

It is easy, if you look at the constructor of the HttpClient signiture you can see it accepts 2 parameters:

public HttpClient (HttpMessageHandler handler, bool disposeHandler);

HttpMessageHandler is your connection manager ! if you do not dispose this object and recreate HttpClient for each request it solves you performance issue.

private static HttpClientHandler clientHandler = new HttpClientHandler();
public async Task MySyncMethod()
{
    using(HttpClient client = new HttpClient(clientHandler,false ))
    {
        client.BaseAddress = new Uri("https://google.com");
        var response = await client.GetAsync("SomeAddress");
        if (response.IsSuccessStatusCode)
        {
            
        }
    }
}


If you are going to use same url for several time you can use http client more than one and it is good ida to keep it alive. But if you have deferent request you should use Using Pattern and let HttpClient recreate for each Unique Url. You can have a dictionary of HttpClients for more than one address if they are a few urls. for more address you need to recreate HttpClient for each request.
Kipping HttpHandler alive help you to create connection per address and it won't create more than one connection for same address. DO NOT FORGET TO SET "DisposeHandler" TO FALSE.




Comments

  1. A better, more clear article: https://blogs.msdn.microsoft.com/shacorn/2016/10/21/best-practices-for-using-httpclient-on-services/

    ReplyDelete
  2. using a new client for each request is an anti-pattern !

    As per Microsoft guidelines,

    HttpClient is intended to be instantiated once and re-used throughout the life of an application. Especially in server applications, creating a new HttpClient instance for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors.

    ReplyDelete
    Replies
    1. Hi mate,
      anti-pattern is not a bad thing every time :D
      this is an old article but let me explain.
      if you use singleton http client with lots of concurrent request, you may get wrong responses for your requests.
      We don’t open socket per request. If you look at the code we used a static HttpClientHandler
      so it will be a socket per address automatically handle by HttpMessageHandler
      in Dot Net Core 3.1 and 5.0 Microsoft did this exactly in HttpClientFactory :)

      Delete
  3. Hi Farshid,

    Your article is superb and with the nitty-gritty details of best practices with regards to the use HttpClient and throughout with applied industry. I would just like to know if this is also an alternative to IHttpClientFactory and is still applicable in NET 6. Thank you mate!

    ReplyDelete

Post a Comment

Popular posts from this blog

Advanced Installation of Openshift Origin 3.7 on CentOS7 with nfs storage

Installing Openshift origin 3.7 with NFS storage The first and for most is planning your architecture In this installation I will try to install 1 master and 3 nodes. your master can use as a node so we will install 1 master and 3 node (use master as a node). do not forget to register an DNS. in this example I will use sample.com 1- Install and run 3 machine with CentOS 7.x 2- set the hostnames of 3 machine # hostnamectl set-hostname master.sample.com # hostnamectl set-hostname node1.sample.com # hostnamectl set-hostname node1.sample.com 3- forward following domains to the machines *.sample.com        => master *.app.sample.com => master node1.sample.com  =>  node1 node2.sample.com  =>  node2 4- generate ssh key in master and copy to all servers as you need to ssh to all machine without password by Ansible # ssh-keygen -t dsa # cat .ssh/id_dsa.pub * copy the keys to all machin in  .ssh/authorized_keys  file  6- install fallowing packages in all

Advanced Installation of Openshift Origin 3.6.0 on CentOS7

To install openshift origin 3.6.0 The first and for most is planning your architecture In this installation I will try to install 1 master and 3 nodes. your master can use as a node so we will install 1 master and 3 node in just 3 machine. do not forget to register an DNS. in this example I will use sample.com 1- Install and run 3 machine with CentOS 7.x 2- set the hostnames of 3 machine # hostnamectl set-hostname master.sample.com # hostnamectl set-hostname node1.sample.com # hostnamectl set-hostname node1.sample.com 3- forward following domains to the machines *.sample.com        => master *.app.sample.com => master node1.sample.com  =>  node1 node2.sample.com  =>  node2   4- generate ssh key in master and copy to all servers as you need to ssh to all machine without password by Ansible # ssh-keygen -t dsa # cat .ssh/id_dsa.pub * copy the keys to all machin in  .ssh/authorized_keys  file  6- install fallowing packages in all machines # y