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.