I figured out how to do this without async/await or TaskCompletionSource , using nested tasks and Task.Unwrap .
First, for the @mikez comment address, here is GetResponseAsync for .NET 4.0:
static public Task<WebResponse> GetResponseTapAsync(this WebRequest request) { return Task.Factory.FromAsync( (asyncCallback, state) => request.BeginGetResponse(asyncCallback, state), (asyncResult) => request.EndGetResponse(asyncResult), null); }
Now, here is the GetResponseWithRetryAsync implementation:
static Task<HttpWebResponse> GetResponseWithRetryAsync(string url, int retries) { if (retries < 0) throw new ArgumentOutOfRangeException(); var request = WebRequest.Create(url); Func<Task<WebResponse>, Task<HttpWebResponse>> proceedToNextStep = null; Func<Task<HttpWebResponse>> doStep = () => { return request.GetResponseTapAsync().ContinueWith(proceedToNextStep).Unwrap(); }; proceedToNextStep = (prevTask) => { if (prevTask.IsCanceled) throw new TaskCanceledException(); if (prevTask.IsFaulted && --retries > 0) return doStep(); // throw if failed or return the result return Task.FromResult((HttpWebResponse)prevTask.Result); }; return doStep(); }
It was an interesting exercise. It works, but I think its path is more complicated than the async/await version.
source share