Home > Software design >  HttpClient and HttpclientHandler Dispose or not dispose, that is the question
HttpClient and HttpclientHandler Dispose or not dispose, that is the question

Time:01-03

I am looking to optimize my code… I have number of API with early same structure for client and handler.

But I have some questions about disposing.

I have read the using statement automatically dispose resources (here HttpClient and HttpClientHandler).

Could I rewrite my code here:

public static async Task<IEnumerable<T>> deletePostsAsync<T>(IEnumerable<string> urls) where T : BaseReturnValues
{
    var httpClientHandler = new HttpClientHandler
    {
        Proxy = new WebProxy(proxy, true),
        UseProxy = IsProxySelected
    };

    using (var client = new HttpClient(httpClientHandler))
    {
        client.BaseAddress = new Uri(URI);
        client.DefaultRequestHeaders.Clear();
        client.DefaultRequestHeaders.Add(Head.key, Head.apikey);

        var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
        var result = await Task.WhenAll(tasks).ConfigureAwait(false);

        return result!;
    }
    async Task<U> DeleteAsync<U>(HttpClient client, string url) where U : BaseReturnValues
    {
        var statusCode = -1;
        var json = "_";
        var isSuccess = false;

        try
        {
            using (HttpResponseMessage response = await client.DeleteAsync(url).ConfigureAwait(false))
            {
                statusCode = (Int32)response.StatusCode;
                json = await response.Content.ReadAsStringAsync();
                isSuccess = response.IsSuccessStatusCode;
            }
        }
        catch (Exception ex)
        {
    //something to catch
        }

           :
        return record;
    }
}

To this piece of code without problem? Disposing resource is always done?

public static async Task<IEnumerable<T>> deletePostsAsync<T>(IEnumerable<string> urls) where T : BaseReturnValues
{
    using (var client = SetClientSettings())
    {
        var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
        var result = await Task.WhenAll(tasks).ConfigureAwait(false);

        return result!;
    }
    async Task<U> DeleteAsync<U>(HttpClient client, string url) where U : BaseReturnValues
    {
           :
           :
        return record;
    }
}

public static Httpclient SetClientSettings()
{
    var httpClientHandler = new HttpClientHandler
    {
        Proxy = new WebProxy(proxy, true),
        UseProxy = IsProxySelected
    };
    var client = new HttpClient(httpClientHandler);
    client.BaseAddress = new Uri(URI);
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Add(Head.key, Head.apikey);

    return client;
}

So I have created a method SetClientSettings and this method create the client, the clienthandler, add some headers to client and return client.

so

var httpClientHandler = new HttpClientHandler
{
    Proxy = new WebProxy(proxy, true),
    UseProxy = IsProxySelected
};

using (var client = new HttpClient(httpClientHandler))
{
    client.BaseAddress = new Uri(URI);
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Add(Head.key, Head.apikey);

    var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
    var result = await Task.WhenAll(tasks).ConfigureAwait(false);

    return result!;
}

is really equivalent to??:

using (var client = SetClientSettings())
{
    var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false));
    var result = await Task.WhenAll(tasks).ConfigureAwait(false);

    return result!;
}

CodePudding user response:

Yes, the code you wrote is equivalent to each other. There's an option in HttpClient contructor to not to dispose message handler - by default, it's set to true. Anyway, as already suggested, you don't have to dispose HTTP client at all. There are reasons for that.

There's alot of nice articles about best practices of using HttpClient. Try to search for IHttpClientFactory.

CodePudding user response:

Your two pieces of code are not equivalent. There is a small difference, that with the first snippet you will dispose the client even when the following lines (e.g. client.BaseAddress = new Uri(URI); or client.DefaultRequestHeaders.Clear();) fail. Which is better. To achieve this with SetClientSettings you would need to wrap everything into try except and .Dispose() on exception.


I have read the using statement automatically dispose resources (here HttpClient and HttpClientHandler).

The using statement turns this:

using (var instance = something)
{
    // body
}

into this

var instance = something;
try
{
    // body
}
finally
{
    if (instance != null)
    {
        instance.Dispose();
    }
}

That's all it does. It is a syntactic sugar.

And so in your particular case the using statement will ensure that .Dispose() is called on HttpClient, regardless of whether exception is thrown or not.

Now, do we have to dispose HttpClient? Well, they say we have to, there's no reason not to believe it. In reality the HttpClient holds sockets under the hood, which have to be closed manually when done with. And so, yes, you should always dispose HttpClient when done with.

That being said, the best thing you can do is to have a singleton HttpClient for the duration of your app, and reuse it. You can tweak it to your needs (e.g. configure it to use pooled connections) for maximal efficiency. In such scenario you don't dispose it at all.

Note: you don't have to worry about disposing HttpClientHandler. By default HttpClient will dispose it when it is disposed itself. This behaviour can be modified by using different constructor.

  • Related