locked
HttpClient Single Instance RRS feed

  • Question

  • User439975351 posted

    I have been reading several articles about the best way to use HttpClient. One article suggests a single instance in the Global.asax file. Does anyone have a definitive answer as to whether this is the best way to implement? The example code in the article is:

    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
     
    namespace HttpClientGuidance
    {
        public class WebApiApplication : System.Web.HttpApplication
        {
            internal static HttpClient httpClientInstance;
     
            protected void Application_Start()
            {
                GlobalConfiguration.Configure(WebApiConfig.Register);            
     
                httpClientInstance = new HttpClient();
                httpClientInstance.DefaultRequestHeaders.ConnectionClose = false;
                
                ServicePointManager.FindServicePoint
                ("some uri").ConnectionLeaseTimeout = 60 * 1000;
                ServicePointManager.FindServicePoint
                ("some other uri").ConnectionLeaseTimeout = 60 * 1000;
                ServicePointManager.FindServicePoint
                ("some other other uri").ConnectionLeaseTimeout = 60 * 1000;
                //etc.....
            }
        }
    }
    Thursday, July 18, 2019 4:30 PM

Answers

  • User1724605321 posted

    Hi 1jus,

    You can create in Global.asax  . A Singleton HttpClient does not respect DNS changes .Re-using an instance of HttpClient means that it holds on to the socket until it is closed so if you have a DNS record update occurring on the server the client will never know until that socket is closed . One easy workaround is to set the keep-alive header to false so the socket will be closed after each request, this obviously results in sub-optimal performance but if you do not care , or you can set the `ConnectionLeaseTimeout ` which specifies how long (in ms) the TCP socket can stay open :

    ServicePointManager.FindServicePoint(endpoint)  
        .ConnectionLeaseTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;

    You can also need to reduce the DNS cache timeout which we can do by setting the DnsRefreshTimeout on the ServicePointManager class like :

    ServicePointManager.DnsRefreshTimeout = (int)1.Minutes().TotalMilliseconds;  
    

    Best Regards,

    Nan Yu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, July 23, 2019 5:22 AM

All replies

  • User475983607 posted

    The standard .NET documentation covers HttpClient in detail and includes recommended patterns.  

    https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netframework-4.8

    This code snippet copied from the docs is perfectly fine.

    public class GoodController : ApiController
    {
        // OK
        private static readonly HttpClient HttpClient;
    
        static GoodController()
        {
            HttpClient = new HttpClient();
        }
    }

    Other options are a Singleton pattern with one Singleton for each service consumed. 

    Dependency inject which is the standard in ASP.NET Core.

    Thursday, July 18, 2019 4:57 PM
  • User439975351 posted

    Thanks mgebhard,

    So would you say that the placement in global.asax would make sense for application wide usage? Also, do you have any suggestions regarding stale DNS/DNS caching?

    Friday, July 19, 2019 7:50 AM
  • User1724605321 posted

    Hi 1jus,

    You can create in Global.asax  . A Singleton HttpClient does not respect DNS changes .Re-using an instance of HttpClient means that it holds on to the socket until it is closed so if you have a DNS record update occurring on the server the client will never know until that socket is closed . One easy workaround is to set the keep-alive header to false so the socket will be closed after each request, this obviously results in sub-optimal performance but if you do not care , or you can set the `ConnectionLeaseTimeout ` which specifies how long (in ms) the TCP socket can stay open :

    ServicePointManager.FindServicePoint(endpoint)  
        .ConnectionLeaseTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;

    You can also need to reduce the DNS cache timeout which we can do by setting the DnsRefreshTimeout on the ServicePointManager class like :

    ServicePointManager.DnsRefreshTimeout = (int)1.Minutes().TotalMilliseconds;  
    

    Best Regards,

    Nan Yu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, July 23, 2019 5:22 AM
  • User439975351 posted

    Thanks Nan Yu :)

    Wednesday, July 24, 2019 8:11 AM