Search code examples
c#.nethttp-headersdotnet-httpclient

How to use the retry-after header to poll API using asp.net http client


I'm kind of new to RESTful consumption using http client in .net and i'm having trouble understanding how to use the retry-after header when polling an external API.

This is what i have to poll currently:

HttpResponseMessage result = null;
var success = false;
var maxAttempts = 7;
var attempts = 0;

using (var client = new HttpClient()) 
{
    do
    {
        var url = "https://xxxxxxxxxxxxxxx";
        result = await client.GetAsync(url);

        attempts++;

        if(result.StatusCode == HttpStatusCode.OK || attempts == maxAttempts) 
           success = true;
    }
    while (!success);
}

return result;

As you can see, i keep polling the endpoint until i've either got an OK response or the max attempts has been reached (to stop continuous looping).

How can i use the retry-after header from the response i get to dictate how long i wait between each of the calls in the loop?

I just cant work out how to apply this to my situation.

Thanks,


Solution

  • HttpClient is intended to be instantiated once per application, rather than per-use

    private static HttpClient client = new HttpClient();
    

    The method (updated with HTTP Host Header usage)

    private static async Task<string> GetDataWithPollingAsync(string url, int maxAttempts, string host = null)
    {
        using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url))
        {
            if (host?.Length > 0) request.Headers.Host = host;
            for (int attempt = 0; attempt < maxAttempts; attempt++)
            {
                TimeSpan delay = default;
                using (HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
                {
                    if (response.IsSuccessStatusCode)
                        return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    delay = response.Headers.RetryAfter.Delta ?? TimeSpan.FromSeconds(1);
                }
                await Task.Delay(delay);
            }
        }
        throw new Exception("Failed to get data from server");
    }
    

    Usage

    try
    {
        string result = await GetDataWithPollingAsync("http://some.url", 7, "www.example.com");
        // received
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
        // failed
    }