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));