0

Using a custom RetryHandler in .NET for HttpClient.

//Create client
var client = new HttpClient(new RetryHandler(new HttpClientHandler()));

//PutAsync
var result = await client.PutAsync(new Uri($"{fileSystem}?resource=filesystem"), null).ConfigureAwait(true);

//Retry Handler
public class RetryHandler : DelegatingHandler
    {
        private const int MaxRetry = 3;
        private const int DelayMilliSeconds = 10000;

        public RetryHandler(HttpMessageHandler innerHandler)
            : base(innerHandler)
        {
        }

        protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            HttpResponseMessage response = null;

            for (int i = 0; i < MaxRetry; i++)
            {
                try
                {

                    CancellationTokenSource source = new CancellationTokenSource(TimeSpan.FromMinutes(5));

                    response = await base.SendAsync(request, source.Token).ConfigureAwait(true);

                    if (response.IsSuccessStatusCode)
                    {
                        return response;
                    }
                }
                catch (Exception e)
                {
                    Thread.Sleep(TimeSpan.FromMilliseconds(Math.Pow(2, i) * DelayMilliSeconds));
                    continue;
                }
                Thread.Sleep(TimeSpan.FromMilliseconds(Math.Pow(2, i) * DelayMilliSeconds));
            }
            return response;
        }

Looks like that it never enters the RetryHandler, getting the following error before entering the RetryHandler.

System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.ObjectDisposedException: Cannot access a closed Stream. at System.IO.Stream.CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) at System.Net.Http.DelegatingStream.CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) at System.Net.Http.StreamToStreamCopy.CopyAsync(Stream source, Stream destination, Int32 bufferSize, Boolean disposeSource, CancellationToken cancellationToken)

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Sky W
  • 1
  • 2
  • 2
    Just a tip: don't use Thread.Sleep when doing async code. Use Task.Delay – JOSEFtw Aug 26 '20 at 18:35
  • Example for the tip above `await Task.Delay(TimeSpan.FromMilliseconds(Math.Pow(2, i) * DelayMilliSeconds));` - never `Thread.Sleep()` in `async` methods. – aepot Aug 26 '20 at 20:51
  • Another tip: never `ConfigureAwait(true)`, it gives overhead but does nothing. But here `ConfigureAwait(false)` is the best choice. In other words: use `false` or not use. – aepot Aug 26 '20 at 20:54
  • Remove `cts`. Looks like GC is disposing it while `response` is in use. Setup HTTP timeout instead. Pass token from arguments to `SendAsync` instead. – aepot Aug 26 '20 at 21:02
  • Also returnung `null` instead of response is not that thing to do here. You must return valid response in any way, regardless of success or not success. – aepot Aug 26 '20 at 21:11
  • Why do you pass `null` for your `PutAsync`'s `content` parameter? – Peter Csala Oct 27 '22 at 13:24

0 Answers0