Singleton httpClient to single Instance of AppService

Viewed 174

First of all sorry for my horrible English :'(.

I'm developing a client to send POST messages to a WebAPI hosted in an Azure AppService. I read the best practicee is use the singleton pattern, so I developed in this way.

public static class UtilHTTP {

    private static readonly ConcurrentDictionary<string, HttpClient> dicClient = new ConcurrentDictionary<string, HttpClient>();

    public static string PostSingleton(string url, string contentType, string accept, string rq, Dictionary<string, string> headers)
    {
        Task<string> response = Fetch(url, contentType, accept, rq, headers);
        response.Wait();
        return response.Result;
    }

    private static HttpClient GetdicClient(string url, string contentType, string accept)
    {
        string key = string.Format("{0}#{1}#{2}", url, contentType, accept);
        if (!dicClient.ContainsKey(key))
        {
            dicClient.GetOrAdd(key, new HttpClient());

            if (!string.IsNullOrEmpty(accept))
            {
                dicClient[key].DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(accept));
            }
        }
        return dicClient[key];
    }

    private static async Task<string> Fetch(string url, string contentType, string accept, string rq, Dictionary<string, string> headers)
    {
        //_http.Timeout = new TimeSpan(0,0,6);
        HttpContent content;
        if (string.IsNullOrEmpty(contentType))
        {
            content = new StringContent(rq, Encoding.UTF8);
        }
        else
        {
            content = new StringContent(rq, Encoding.UTF8, contentType);
        }

        if (headers != null)
        {
            foreach (KeyValuePair<string, string> h in headers)
            {
                content.Headers.Add(h.Key, h.Value);
            }
        }

        HttpResponseMessage response = await GetdicClient(url, contentType, accept).PostAsync(url, content);
        string resultContent = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
        {
            resultContent = response.ReasonPhrase;
        }

        return resultContent;
    }

}

I have two instances of the service in the AppService, but all the requests are going to the same instance, so I can't scalate the service and the performance isn't really good.

Insights Performance

Is it something wrong in the code? Do you think is a problem in the Server side? Must I use another pattern?

Thank you very much!

1 Answers

It appears at first glance that you're doing the singleton HttpClient (per client) correctly. The only issue I could see with it would be if you have multiple calls to the same URL with different parameters in the URL, those parameters would cause a new client to be created. I don't know that you're doing that, though, so there may be no problem here.

The other issue you discussed (about all requests going to the same instance of your app service), could be related to ARR affinity (what's called "sticky-session). Check your app service settings (Configuration -> General settings) to make sure it's turned off:

ARR Affinity

Related