1

Wanted to verify if HttpCLient instance should be created outside method passed to polly for ExecuteAsync, or in?

My current usage varies between the two options and I am not sure which is the correct one?

Also, if it incurs some drawbacks, or possible memory leaks, etc. ?

Get:

var client = new HttpClient(new NativeMessageHandler()) { Timeout = new TimeSpan(0, 0, TimeOutSec) };

var httpResponse = await AuthenticationOnUnauthorizePolicy.ExecuteAsync(async () =>
{
    UpdateClientHeader(client, correlationId);
    return await client.GetAsync(url, token);
});

Post:

var httpResponse = await AuthenticationOnUnauthorizePolicy.ExecuteAsync(async () =>
{
    using (var client = new HttpClient(new NativeMessageHandler()) { Timeout = new TimeSpan(0, 0, TimeOutSec) })
    {
        UpdateClientHeader(client, correlationId);
        WriteNetworkAccessStatusToLog();
        return await client.PostAsync(url, content);
    }
});

The policy used here:

AuthenticationOnUnauthorizePolicy = Policy
     .HandleResult<HttpResponseMessage>(reposnse => reposnse.StatusCode == HttpStatusCode.Unauthorized)
     .RetryAsync(1, onRetryAsync:
     async (response, count, context) =>
     {
         _logger.Info("Unauthorized Response! Retrying Authentication...");
         await Authenticate();
     });

Appreciates any comments on the code above.

Is there a correct way?

Do I need to use the Context to get the client again, or is my usage okay?


Update:

Authenticate method:

public virtual async Task Authenticate()
{
    // lock it - only one request can request token
    if (Interlocked.CompareExchange(ref _isAuthenticated, 1, 0) == 0)
    {
        var result = new WebResult();
        var loginModel = new LoginModel
        {
            email = _settingService.Email,
            password = _settingService.Password
        };

        var url = ......
        var correlationId = Guid.NewGuid().ToString();

        try
        {
            var stringObj = JsonHelper.SerializeObject(loginModel);
            HttpContent content = new StringContent(stringObj, Encoding.UTF8, HttpConsts.JsonMediaType);

            using (var client = new HttpClient(new NativeMessageHandler()) { Timeout = new TimeSpan(0, 0, TimeOutSec) }
            )
            {
                UpdateClientHeader(client, correlationId, useToken: false); // not token, we need new one
                using (var httpResponse = await client.PostAsync(url, content))
                {
                    var sReader = await httpResponse.Content.ReadAsStringAsync();
                    await HandleRequest(result, sReader, httpResponse, correlationId, url, "result");
                }
            }
            if (result != null && !result.HasError)
            {
                _loginToken = result.Token;
            }
        }
        catch (Exception ex)
        {
            // Log error
        }
        finally
        {
            _isAuthenticated = 0;
        }
    }
}

Update client headr method:

if (_loginToken != null &&
                !client.DefaultRequestHeaders.Contains("Token"))
            {
                client.DefaultRequestHeaders.Add("Token", _loginToken );
            }
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(HttpConsts.JsonMediaType));
17
  • Can you please share with us the code of Authenticate and UpdateClientHeader as well? Commented Oct 18, 2021 at 10:35
  • Updated with methods. Commented Oct 18, 2021 at 11:27
  • 1
    don't put a HttpClient in a using block. It doesn't work that way. Use a static instance. Commented Oct 18, 2021 at 11:33
  • How do you get the _loginToken inside UpdateClientHeader? How is it updated? Commented Oct 18, 2021 at 12:08
  • @JHBonarius Isn't static instance dangerous to use? Can't the client dispose after timeout or some error state, and I'll have to manage clients? create, remove, update and dispose them? Commented Oct 19, 2021 at 11:07

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.