Re-authorization and onRetry with Polly

Full source code available here.

Want to learn more about Polly? Check out my Pluralsight course on it.

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.

 1public class ValuesController : ApiController
 2{
 3    readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy;
 4    private HttpClient _httpClient;
 5    public ValuesController()
 6    {
 7        _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
 8                r => r.StatusCode == HttpStatusCode.InternalServerError ||
 9                     r.StatusCode == HttpStatusCode.Unauthorized)
10            .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt), onRetry: (response, timespan) =>
11            {
12                if (response.Result.StatusCode == HttpStatusCode.Unauthorized)
13                {
14                    PerformReauthorization();
15                }
16            });
17    }

The onRetry delegate is the new part -

1onRetry: (response, timespan) =>
2{
3	if (response.Result.StatusCode == HttpStatusCode.Unauthorized)
4	{
5		PerformReauthorization();
6	}
7}

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.

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

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.

 1private HttpClient GetHttpClient(string authCookieValue)
 2{
 3    var cookieContainer = new CookieContainer();
 4    var handler = new HttpClientHandler() {CookieContainer = cookieContainer};
 5    cookieContainer.Add(new Uri("http://localhost"),new Cookie("Auth", authCookieValue));
 6    _httpClient = new HttpClient(handler);
 7    _httpClient.BaseAddress = new Uri(@"http://localhost:2629/api/");
 8
 9    _httpClient.DefaultRequestHeaders.Accept.Clear();
10    _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
11    return _httpClient;
12}

Full source code available here.

comments powered by Disqus

Related