using System.Collections.Specialized;
using System.Diagnostics;
using System.Diagnostics.Contracts;
+using System.IO;
using System.Net;
using System.Runtime.Serialization;
+using System.Threading.Tasks;
namespace Pithos.Network
{
CopyHeaders(other);
Timeout = other.Timeout;
Retries = other.Retries;
- BaseAddress = other.BaseAddress;
-
+ BaseAddress = other.BaseAddress;
foreach (var parameter in other.Parameters)
{
protected override WebResponse GetWebResponse(WebRequest request)
{
+ try
+ {
+
var response = (HttpWebResponse)base.GetWebResponse(request);
StatusCode = response.StatusCode;
StatusDescription = response.StatusDescription;
return response;
+ }
+ catch (WebException exc)
+ {
+ if (exc.Response!=null && exc.Response.ContentLength > 0)
+ {
+ string content = GetContent(exc.Response);
+ Trace.TraceError(content);
+ }
+ throw;
+ }
+ }
+
+ private static string GetContent(WebResponse webResponse)
+ {
+ string content;
+ using (var stream = webResponse.GetResponseStream())
+ using (var reader = new StreamReader(stream))
+ {
+ content = reader.ReadToEnd();
+ }
+ return content;
}
public string DownloadStringWithRetry(string address,int retries=0)
var actualAddress = GetActualAddress(address);
+ TraceStart("GET",actualAddress);
+
var actualRetries = (retries == 0) ? Retries : retries;
- var func = Retry(() =>
+
+ var task = Retry(() =>
{
- var uriString = String.Join("/", BaseAddress, actualAddress);
+ var uriString = String.Join("/", BaseAddress.TrimEnd('/'), actualAddress);
var content = base.DownloadString(uriString);
if (StatusCode == HttpStatusCode.NoContent)
}, actualRetries);
- var result = func();
+ var result = task.Result;
return result;
}
if (address == null)
throw new ArgumentNullException("address");
- var actualAddress = GetActualAddress(address);
-
+ var actualAddress = GetActualAddress(address);
var actualRetries = (retries == 0) ? Retries : retries;
- var func = Retry(() =>
+
+ var task = Retry(() =>
{
var uriString = String.Join("/",BaseAddress ,actualAddress);
var uri = new Uri(uriString);
if (ResponseHeaders!=null)
ResponseHeaders.Clear();
+ TraceStart(method, uriString);
+
var response = (HttpWebResponse)GetWebResponse(request);
StatusCode = response.StatusCode;
StatusDescription = response.StatusDescription;
return 0;
}, actualRetries);
- func();
+ task.Wait();
+ }
+
+ private static void TraceStart(string method, string actualAddress)
+ {
+ Trace.WriteLine(String.Format("[{0}] {1} {2}", method, DateTime.Now, actualAddress));
}
private string GetActualAddress(string address)
throw new ArgumentNullException("address");
var actualRetries = (retries == 0) ? Retries : retries;
- var func = Retry(() =>
+ var task = Retry(() =>
{
var content = base.DownloadString(address);
}, actualRetries);
- var result = func();
+ var result = task.Result;
return result;
}
throw new WebException(String.Format("{0} with code {1} - {2}", message, StatusCode, StatusDescription));
}
- private Func<T> Retry<T>(Func< T> original, int retryCount)
+ /*private Func<T> Retry<T>(Func< T> original, int retryCount)
{
return () =>
{
}
}
};
+ }*/
+
+ private Task<T> Retry<T>(Func< T> original, int retryCount)
+ {
+ return Task.Factory.StartNew(() => original()).ContinueWith(_original =>
+ {
+ if(_original.IsFaulted )
+ {
+ var e = _original.Exception.InnerException;
+ if (e is WebException)
+ {
+ var we = (e as WebException);
+
+ var statusCode = HttpStatusCode.RequestTimeout;
+ if (we.Response != null)
+ {
+ statusCode = ((HttpWebResponse) we.Response).StatusCode;
+ this.StatusCode = statusCode;
+ }
+
+ if (we.Status==WebExceptionStatus.Timeout ||
+ (we.Status==WebExceptionStatus.ProtocolError && statusCode==HttpStatusCode.ServiceUnavailable))
+ {
+ TimedOut = true;
+ if (retryCount == 0)
+ {
+ Trace.TraceError("[ERROR] Timed out too many times. {0}\n", e);
+ throw new RetryException("Timed out too many times.", e);
+ }
+ Trace.TraceError(
+ "[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}", Timeout,
+ retryCount, e);
+ return Retry(original, retryCount - 1);
+ }
+
+ if (statusCode==HttpStatusCode.NotFound)
+ return Task<T>.Factory.StartNew(() => default(T));
+ }
+ throw e;
+ }
+ else
+ return Task<T>.Factory.StartNew(() => _original.Result);
+ }).Unwrap();
}