Capturing Redirects with HttpClient

Home / Capturing Redirects with HttpClient

A while back, I blogged about a pattern of accessing API’s with .NET’s HttpClient. In practice, one problem with .NET’s HttpClient is that it doesn’t provide any insight regarding Http redirects.


By default, HttpClient follows redirects without making any fuss. Most of the time, letting HttpClient follow redirects for you works well enough. In a current application, though, when using generic/reusable service methods, I need to know the final redirect in some cases. The final redirect lets me know when I can trigger other actions in a particular work-flow.

If we pass an HttpClientHandler to the HttpClient, it has a property to allow prevention of automatic redirection. The property is “AllowAutoRedirect.” The setup then looks like the below code. Since the HttpClient doesn’t follow redirects, we can check the status code and perform our own logic on redirects. You can see in the handling of the redirect, the “MakeRequest” method effectively becomes a recursive routine. A redirect can specify an absolute or relative URL. This must be handled as indicated in the code as well.

public bool MakeRequest(url)
{
    using (var client = new HttpClient(new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip }) { Timeout = _timeout })
    {
        var request = new HttpRequestMessage()
        {
            RequestUri = new Uri(url),
            Method = HttpMethod.Get
        };

        HttpResponseMessage response = client.SendAsync(request).Result;
        var statusCode = (int)response.StatusCode;

        // We want to handle redirects ourselves so that we can determine the final redirect Location (via header)
        if (statusCode >= 300 && statusCode <= 399)
        {
            var redirectUri = response.Headers.Location;
            if (!redirectUri.IsAbsoluteUri)
            {
                redirectUri = new Uri(request.RequestUri.GetLeftPart(UriPartial.Authority) + redirectUri);
            }
            _status.AddStatus(string.Format("Redirecting to {0}", redirectUri));
            return MakeRequest(redirectUri);
        }
        else if (!response.IsSuccessStatusCode)
        {
            throw new Exception();
        }

        return true;
    }
}

2 thoughts on “Capturing Redirects with HttpClient”

    1. Notice that this post predates the one you referenced. 😉

      Also, it was intended to be illustrative. If you care to know, this is the production-type pattern I use for managing HttpClient as a singleton:

      /// <summary>
      /// Inject as a singleton to avoid multiple instances of HttpClient
      /// </summary>
      public class ApiService : IApiService
      {
          private HttpClient _httpClient;
          private TimeSpan _timeout;
          private ILogger _log;
       
          private static string _xmlMediaType = "text/xml";
          private static string _jsonMediaType = "application/json";
          private static string _formMediaType = "application/x-www-form-urlencoded";
          private static MediaTypeWithQualityHeaderValue _jsonAcceptHeader = new MediaTypeWithQualityHeaderValue(_jsonMediaType);
      
          private HttpClient Client
          {
              get
              {
                  if (_httpClient == null)
                  {
                      var httpClientHandler = new HttpClientHandler()
                      {
                          AllowAutoRedirect = true,
                          AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
                      };
       
                      _httpClient = new HttpClient(httpClientHandler) { Timeout = _timeout };
                      _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(_xmlMediaType));
                      _httpClient.DefaultRequestHeaders.ConnectionClose = true;
                  }
      
                  return _httpClient;
              }
          }
      }
      

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.