Re-authorization and onRetry with Polly

Full source code available here.

In a previous post I showed how to use Polly to make a simple call, retrying in the event of failure. In another I showed how to let a request fail and process the response.

In this post I will show a retry where a delegate is called as part of the retry. A common use case for this is reauthorizing after an Unauthorized response.

The difference between this policy and the ones in my previous posts is very small.

public class ValuesController : ApiController
{
    readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy;
    private HttpClient _httpClient;
    public ValuesController()
    {
        _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
                r => r.StatusCode == HttpStatusCode.InternalServerError ||
                     r.StatusCode == HttpStatusCode.Unauthorized)
            .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt), onRetry: (response, timespan) =>
            {
                if (response.Result.StatusCode == HttpStatusCode.Unauthorized)
                {
                    PerformReauthorization();
                }
            });
    }

The onRetry delegate is the new part –

onRetry: (response, timespan) =>
{
	if (response.Result.StatusCode == HttpStatusCode.Unauthorized)
	{
		PerformReauthorization();
	}
}

In my PerformReauthorization I create a new HttpClient and pass it the new authorization code. For simplicity I am passing a code in the cookie of my request, you could of course use Basic Authentication or any another technique.

private void PerformReauthorization()
{
    // here you would get a new token, call some other service, etc.
    _httpClient = GetHttpClient("GoodAuthCode"); // pass in the good auth token
}

The important thing to note is that my HttpClient instance is class level, meaning it can be accessed from PerformReauthorization.

The call to the web service remains the same.

HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => _httpClient.GetAsync(requestEndpoint))

I’ll post of fallbacks soon, they allow a default value to be returned in the event of repeated failures.

For completeness here is GetHttpClient.

private HttpClient GetHttpClient(string authCookieValue)
{
    var cookieContainer = new CookieContainer();
    var handler = new HttpClientHandler() {CookieContainer = cookieContainer};
    cookieContainer.Add(new Uri("http://localhost"),new Cookie("Auth", authCookieValue));
    _httpClient = new HttpClient(handler);
    _httpClient.BaseAddress = new Uri(@"http://localhost:2629/api/");

    _httpClient.DefaultRequestHeaders.Accept.Clear();
    _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    return _httpClient;
}

Full source code available here.

Leave a Reply

Your email address will not be published. Required fields are marked *