2 using System.Collections.Generic;
3 using System.Diagnostics;
10 using System.Reflection;
12 using System.Threading;
13 using Hammock.Authentication;
14 using Hammock.Caching;
15 using Hammock.Extensions;
16 using Hammock.Retries;
17 using Hammock.Serialization;
20 using Hammock.Streaming;
21 using Hammock.Web.Mocks;
24 using Hammock.Silverlight.Compat;
32 public class RestClient : RestBase, IRestClient
34 private const string MockContentType = "mockContentType";
35 private const string MockScheme = "mockScheme";
36 private const string MockProtocol = "mock";
37 private const string MockStatusDescription = "mockStatusDescription";
38 private const string MockContent = "mockContent";
39 private const string MockHttpMethod = "mockHttpMethod";
40 private const string EndStreamingContent = "END STREAMING";
42 public virtual string Authority { get; set; }
44 public virtual event EventHandler<FileProgressEventArgs> FileProgress;
45 public virtual void OnFileProgress(FileProgressEventArgs args)
47 var handler = FileProgress;
54 public virtual event EventHandler<RetryEventArgs> BeforeRetry;
55 public virtual void OnBeforeRetry(RetryEventArgs args)
57 var handler = BeforeRetry;
65 public virtual bool HasElevatedPermissions { get; set; }
67 /// Used to set the name of the "Accept" header used by your Silverlight proxy.
69 public virtual string SilverlightAcceptEncodingHeader { get; set;}
72 /// Used to set the name of the "User-Agent" header used by your Silverlight proxy.
74 public virtual string SilverlightUserAgentHeader { get; set;}
78 private bool _firstTry = true;
80 private int _remainingRetries;
82 private readonly object _timedTasksLock = new object();
83 private readonly object _streamingLock = new object();
84 private WebQuery _streamQuery;
86 private readonly Dictionary<RestRequest, TimedTask> _tasks = new Dictionary<RestRequest, TimedTask>();
91 public RestResponse<dynamic> RequestDynamic(RestRequest request)
93 var query = RequestImpl(request);
95 dynamic response = BuildResponseFromResultDynamic(request, query);
101 public virtual RestResponse Request(RestRequest request)
103 var query = RequestImpl(request);
105 return BuildResponseFromResult(request, query);
108 public virtual RestResponse<T> Request<T>(RestRequest request)
110 var query = RequestImpl(request);
112 return BuildResponseFromResult<T>(request, query);
115 public RestResponse Request()
117 var query = RequestImpl(null);
119 return BuildResponseFromResult(null, query);
122 public RestResponse<T> Request<T>()
124 var query = RequestImpl(null);
126 return BuildResponseFromResult<T>(null, query);
129 private static bool _mockFactoryInitialized;
131 private WebQuery RequestImpl(RestRequest request)
134 WebQuery query = null;
135 request = request ?? new RestRequest();
137 var retryPolicy = GetRetryPolicy(request);
140 _remainingRetries = (retryPolicy != null ? retryPolicy.RetryCount : 0) + 1;
144 while (_remainingRetries > 0)
146 request = PrepareRequest(request, out uri, out query);
148 var url = uri.ToString();
150 if (RequestExpectsMock(request))
152 if (!_mockFactoryInitialized)
154 WebRequest.RegisterPrefix(MockProtocol, new MockWebRequestFactory());
155 _mockFactoryInitialized = true;
158 url = BuildMockRequestUrl(request, query, url);
161 UpdateRetryState(request);
163 WebException exception;
164 if (!RequestWithCache(request, query, url, out exception) &&
165 !RequestMultiPart(request, query, url, out exception))
167 query.Request(url, out exception);
170 query.Result.Exception = exception;
171 var current = query.Result;
173 if (retryPolicy != null)
175 var retry = _remainingRetries > 0 && ShouldRetry(retryPolicy, exception, current);
180 if (_remainingRetries > 0)
182 query.Result = new WebQueryResult { TimesTried = GetIterationCount(request) };
184 OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
189 _remainingRetries = 0;
194 _remainingRetries = 0;
198 _firstTry = _remainingRetries == 0;
202 private RestRequest PrepareRequest(RestRequest request, out Uri uri, out WebQuery query)
204 request = request ?? new RestRequest();
205 uri = request.BuildEndpoint(this);
206 query = GetQueryFor(request, uri);
207 SetQueryMeta(request, query);
211 private bool RequestMultiPart(RestBase request, WebQuery query, string url, out WebException exception)
213 var parameters = GetPostParameters(request);
214 if (parameters == null || parameters.Count() == 0)
220 // [DC]: Default to POST if no method provided
221 query.Method = query.Method != WebMethod.Post && query.Method != WebMethod.Put ? WebMethod.Post : query.Method;
222 query.Request(url, parameters, out exception);
226 private bool RequestWithCache(RestBase request, WebQuery query, string url, out WebException exception)
228 var cache = GetCache(request);
235 var options = GetCacheOptions(request);
242 // [DC]: This is currently prefixed to the full URL
243 var function = GetCacheKeyFunction(request);
244 var key = function != null ? function.Invoke() : "";
246 switch (options.Mode)
248 case CacheMode.NoExpiration:
249 query.Request(url, key, cache, out exception);
251 case CacheMode.AbsoluteExpiration:
252 var expiry = options.Duration.FromNow();
253 query.Request(url, key, cache, expiry, out exception);
255 case CacheMode.SlidingExpiration:
256 query.Request(url, key, cache, options.Duration, out exception);
259 throw new NotSupportedException("Unknown CacheMode");
265 private void UpdateRepeatingRequestState(RestBase request)
267 var taskState = request.TaskState ?? TaskState;
268 if (taskState == null)
272 taskState.RepeatCount++;
273 taskState.LastRepeat = DateTime.Now;
276 private void UpdateRetryState(RestBase request)
278 var retryState = request.RetryState ?? RetryState;
279 if (retryState == null)
284 retryState.RepeatCount++;
285 retryState.LastRepeat = DateTime.Now;
288 private static bool ShouldRetry(RetryPolicy retryPolicy,
290 WebQueryResult current)
293 foreach (var condition in retryPolicy.RetryConditions.OfType<RetryErrorCondition>())
295 if (exception == null)
299 retry |= condition.RetryIf(exception);
302 foreach (var condition in retryPolicy.RetryConditions.OfType<RetryResultCondition>())
308 retry |= condition.RetryIf(current);
311 foreach (var condition in retryPolicy.RetryConditions.OfType<IRetryCustomCondition>())
313 var innerType = condition.GetDeclaredTypeForGeneric(typeof(IRetryCondition<>));
314 if (innerType == null)
320 var retryType = typeof(RetryCustomCondition<>).MakeGenericType(innerType);
321 if (retryType == null)
327 var func = condition.GetValue("ConditionFunction") as MulticastDelegate;
333 // Call the function to find the retry evaluator
334 #if !Smartphone && !NETCF
335 var t = func.DynamicInvoke(null);
337 var del = func.GetInvocationList().FirstOrDefault();
338 var t = del.Method.Invoke(func, null);
341 // Invoke the retry predicate and pass the evaluator
342 var p = condition.GetValue("RetryIf");
343 var r = p.GetType().InvokeMember("Invoke",
344 BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
345 null, p, new[] { t });
353 private string BuildMockRequestUrl(RestRequest request,
357 if (url.Contains("https"))
359 url = url.Replace("https", MockProtocol);
361 query.Parameters.Add(MockScheme, "https");
363 if (url.Contains("http"))
365 url = url.Replace("http", MockProtocol);
366 query.Parameters.Add(MockScheme, "http");
369 if (request.ExpectStatusCode.HasValue)
371 query.Parameters.Add("mockStatusCode", ((int)request.ExpectStatusCode.Value).ToString());
372 if (request.ExpectStatusDescription.IsNullOrBlank())
374 query.Parameters.Add(MockStatusDescription, request.ExpectStatusCode.ToString());
377 if (!request.ExpectStatusDescription.IsNullOrBlank())
379 query.Parameters.Add(MockStatusDescription, request.ExpectStatusDescription);
382 query.Parameters.Add(
383 MockHttpMethod, request.Method.ToString().ToUpper()
386 var expectEntity = SerializeExpectEntity(request);
387 if (expectEntity != null)
389 query.Parameters.Add(MockContent, expectEntity.Content);
390 query.Parameters.Add(MockContentType, expectEntity.ContentType);
391 query.HasEntity = true; // Used with POSTs
395 if (!request.ExpectContent.IsNullOrBlank())
397 query.Parameters.Add(MockContent, request.ExpectContent);
398 query.Parameters.Add(MockContentType,
399 !request.ExpectContentType.IsNullOrBlank()
400 ? request.ExpectContentType
406 if (!request.ExpectContentType.IsNullOrBlank())
408 query.Parameters.Add(
409 MockContentType, request.ExpectContentType
415 if (request.ExpectHeaders.Count > 0)
417 var names = new StringBuilder();
418 var values = new StringBuilder();
420 foreach (var key in request.ExpectHeaders.AllKeys)
423 values.Append(request.ExpectHeaders[key].Value);
425 if (count < request.ExpectHeaders.Count)
432 query.Parameters.Add("mockHeaderNames", names.ToString());
433 query.Parameters.Add("mockHeaderValues", values.ToString());
439 private static bool RequestExpectsMock(RestRequest request)
441 return request.ExpectEntity != null ||
442 request.ExpectHeaders.Count > 0 ||
443 request.ExpectStatusCode.HasValue ||
444 !request.ExpectContent.IsNullOrBlank() ||
445 !request.ExpectContentType.IsNullOrBlank() ||
446 !request.ExpectStatusDescription.IsNullOrBlank();
449 private ICache GetCache(RestBase request)
451 return request.Cache ?? Cache;
454 private IEnumerable<HttpPostParameter> GetPostParameters(RestBase request)
456 if (request.PostParameters != null)
458 foreach (var parameter in request.PostParameters)
460 yield return parameter;
464 if (PostParameters == null)
469 foreach (var parameter in PostParameters)
471 yield return parameter;
475 private CacheOptions GetCacheOptions(RestBase request)
477 return request.CacheOptions ?? CacheOptions;
480 private Func<string> GetCacheKeyFunction(RestBase request)
482 return request.CacheKeyFunction ?? CacheKeyFunction;
485 private string GetProxy(RestBase request)
487 return request.Proxy ?? Proxy;
490 private string GetUserAgent(RestBase request)
492 var userAgent = request.UserAgent.IsNullOrBlank()
498 private ISerializer GetSerializer(RestBase request)
500 return request.Serializer ?? Serializer;
503 private IWebCredentials GetWebCredentials(RestBase request)
505 var credentials = request.Credentials ?? Credentials;
509 private IWebQueryInfo GetInfo(RestBase request)
511 var info = request.Info ?? Info;
515 private bool GetTraceEnabled(RestBase request)
517 var info = request.TraceEnabled || TraceEnabled;
521 private TimeSpan? GetTimeout(RestBase request)
523 return request.Timeout ?? Timeout;
526 private DecompressionMethods? GetDecompressionMethods(RestBase request)
528 return request.DecompressionMethods ?? DecompressionMethods;
531 private WebMethod GetWebMethod(RestBase request)
533 var method = !request.Method.HasValue
537 : request.Method.Value;
542 private byte[] GetPostContent(RestBase request)
544 var content = request.PostContent ?? PostContent;
548 private RetryPolicy GetRetryPolicy(RestBase request)
550 var policy = request.RetryPolicy ?? RetryPolicy;
554 private Encoding GetEncoding(RestBase request)
556 var encoding = request.Encoding ?? Encoding;
561 private bool GetFollowRedirects(RestBase request)
563 var redirects = request.FollowRedirects ?? FollowRedirects ?? false;
568 private TaskOptions GetTaskOptions(RestBase request)
570 var options = request.TaskOptions ?? TaskOptions;
574 private StreamOptions GetStreamOptions(RestBase request)
576 var options = request.StreamOptions ?? StreamOptions;
580 private object GetTag(RestBase request)
582 var tag = request.Tag ?? Tag;
587 public virtual IAsyncResult BeginRequest(RestRequest request, RestCallback callback, object userState)
589 return BeginRequestImpl(request, callback, null, null, false /* isInternal */, userState);
592 public virtual IAsyncResult BeginRequest<T>(RestRequest request, RestCallback<T> callback, object userState)
594 return BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
597 public IAsyncResult BeginRequest()
599 return BeginRequest(null /* request */, null /* callback */);
602 public IAsyncResult BeginRequest<T>()
604 return BeginRequest(null /* request */, null /* callback */);
608 public IAsyncResult BeginRequestDynamic()
610 return BeginRequestDynamic(null /* request */, null /* callback */);
614 public virtual IAsyncResult BeginRequest(RestRequest request, RestCallback callback)
616 return BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
619 public virtual IAsyncResult BeginRequest<T>(RestRequest request, RestCallback<T> callback)
621 return BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
625 public virtual IAsyncResult BeginRequestDynamic(RestRequest request, RestCallback<dynamic> callback)
627 return BeginRequestImplDynamic(request, callback, null, null, false /* isInternal */, null);
630 public virtual IAsyncResult BeginRequestDynamic(RestRequest request, RestCallback<dynamic> callback, object userState)
632 return BeginRequestImplDynamic(request, callback, null, null, false /* isInternal */, userState);
636 public virtual IAsyncResult BeginRequest(RestCallback callback)
638 return BeginRequestImpl(null, callback, null, null, false /* isInternal */, null);
641 public virtual IAsyncResult BeginRequest(RestRequest request)
643 return BeginRequest(request, null, null);
646 public IAsyncResult BeginRequest(RestRequest request, object userState)
648 return BeginRequest(request, null, userState);
651 public virtual IAsyncResult BeginRequest<T>(RestRequest request)
653 return BeginRequest<T>(request, null, null);
656 public IAsyncResult BeginRequest<T>(RestRequest request, object userState)
658 return BeginRequest<T>(request, null, userState);
661 public virtual IAsyncResult BeginRequest<T>(RestCallback<T> callback)
663 return BeginRequest(null, callback, null);
666 public virtual void BeginRequest(RestRequest request, RestCallback callback, object userState)
668 BeginRequestImpl(request, callback, null, null, false /* isInternal */, userState);
671 public virtual void BeginRequest<T>(RestRequest request, RestCallback<T> callback, object userState)
673 BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
676 public virtual void BeginRequest()
678 BeginRequest(null /* request */, null /* callback */);
681 public virtual void BeginRequest<T>()
683 BeginRequest(null /* request */, null /* callback */);
686 public virtual void BeginRequest(RestRequest request, RestCallback callback)
688 BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
691 public virtual void BeginRequest<T>(RestRequest request, RestCallback<T> callback)
693 BeginRequestImpl(request, callback, null, null, false /* isInternal */, null);
696 public virtual void BeginRequest(RestCallback callback)
698 BeginRequestImpl(null, callback, null, null, false /* isInternal */, null);
701 public virtual void BeginRequest(RestRequest request)
703 BeginRequest(request, null, null);
706 public void BeginRequest(RestRequest request, object userState)
708 BeginRequest(request, null, userState);
711 public virtual void BeginRequest<T>(RestRequest request)
713 BeginRequest<T>(request, null, null);
716 public void BeginRequest<T>(RestRequest request, object userState)
718 BeginRequest<T>(request, null, userState);
721 public virtual void BeginRequest<T>(RestCallback<T> callback)
723 BeginRequest(null, callback, null);
728 public virtual RestResponse EndRequest(IAsyncResult result)
731 var webResult = EndRequestImpl(result);
733 var webResult = EndRequestImpl(result, null);
735 return webResult.AsyncState as RestResponse;
738 public virtual RestResponse EndRequest(IAsyncResult result, TimeSpan timeout)
740 var webResult = EndRequestImpl(result, timeout);
741 return webResult.AsyncState as RestResponse;
744 public virtual RestResponse<T> EndRequest<T>(IAsyncResult result)
747 var webResult = EndRequestImpl<T>(result);
749 var webResult = EndRequestImpl<T>(result, null);
751 return webResult.AsyncState as RestResponse<T>;
755 public virtual RestResponse<dynamic> EndRequestDynamic(IAsyncResult result)
758 var webResult = EndRequestImplDynamic(result);
760 var webResult = EndRequestImplDynamic<T>(result, null);
762 return webResult.AsyncState as RestResponse<dynamic>;
766 public virtual RestResponse<T> EndRequest<T>(IAsyncResult result, TimeSpan timeout)
768 var webResult = EndRequestImpl<T>(result, timeout);
769 return webResult.AsyncState as RestResponse<T>;
773 private WebQueryAsyncResult EndRequestImpl(IAsyncResult result, TimeSpan? timeout = null)
776 private WebQueryAsyncResult EndRequestImpl(IAsyncResult result, TimeSpan? timeout)
779 var webResult = result as WebQueryAsyncResult;
780 if (webResult == null)
782 throw new InvalidOperationException("The IAsyncResult provided was not for this operation.");
785 var tag = (Triplet<RestRequest, RestCallback, object>)webResult.Tag;
787 if (RequestExpectsMock(tag.First))
789 // [DC]: Mock results come via InnerResult
790 webResult = (WebQueryAsyncResult)webResult.InnerResult;
793 if (webResult.CompletedSynchronously)
795 var query = webResult.AsyncState as WebQuery;
799 CompleteWithQuery(query, tag.First, tag.Second, webResult);
804 webResult = CompleteWithMockWebResponse(result, webResult, tag);
808 if (!webResult.IsCompleted)
813 var millisecondsTimeout = Convert.ToInt32(timeout.Value.TotalMilliseconds);
814 webResult.AsyncWaitHandle.WaitOne(millisecondsTimeout, false);
816 webResult.AsyncWaitHandle.WaitOne(timeout.Value);
821 webResult.AsyncWaitHandle.WaitOne();
828 private WebQueryAsyncResult EndRequestImpl<T>(IAsyncResult result, TimeSpan? timeout = null)
830 private WebQueryAsyncResult EndRequestImpl<T>(IAsyncResult result, TimeSpan? timeout)
833 var webResult = result as WebQueryAsyncResult;
834 if (webResult == null)
836 throw new InvalidOperationException("The IAsyncResult provided was not for this operation.");
839 var tag = (Triplet<RestRequest, RestCallback<T>, object>)webResult.Tag;
841 if (RequestExpectsMock(tag.First))
843 // [DC]: Mock results come via InnerResult
844 webResult = (WebQueryAsyncResult)webResult.InnerResult;
847 if (webResult.CompletedSynchronously)
849 var query = webResult.AsyncState as WebQuery;
853 CompleteWithQuery(query, tag.First, tag.Second, webResult);
858 webResult = CompleteWithMockWebResponse(result, webResult, tag);
862 if (!webResult.IsCompleted)
867 var millisecondsTimeout = Convert.ToInt32(timeout.Value.TotalMilliseconds);
868 webResult.AsyncWaitHandle.WaitOne(millisecondsTimeout, false);
870 webResult.AsyncWaitHandle.WaitOne(timeout.Value);
875 webResult.AsyncWaitHandle.WaitOne();
884 private WebQueryAsyncResult EndRequestImplDynamic(IAsyncResult result, TimeSpan? timeout = null)
886 private WebQueryAsyncResult EndRequestImplDynamic(IAsyncResult result, TimeSpan? timeout)
889 var webResult = result as WebQueryAsyncResult;
890 if (webResult == null)
892 throw new InvalidOperationException("The IAsyncResult provided was not for this operation.");
895 var tag = (Triplet<RestRequest, RestCallback<dynamic>, object>) webResult.Tag;
897 if (RequestExpectsMock(tag.First))
899 // [DC]: Mock results come via InnerResult
900 webResult = (WebQueryAsyncResult) webResult.InnerResult;
903 if (webResult.CompletedSynchronously)
905 var query = webResult.AsyncState as WebQuery;
909 CompleteWithQueryDynamic(query, tag.First, tag.Second, webResult);
914 webResult = CompleteWithMockWebResponse(result, webResult, tag);
918 if (!webResult.IsCompleted)
922 webResult.AsyncWaitHandle.WaitOne(timeout.Value);
926 webResult.AsyncWaitHandle.WaitOne();
933 private WebQueryAsyncResult CompleteWithMockWebResponse<T>(
935 IAsyncResult webResult,
936 Triplet<RestRequest, RestCallback<T>, object> tag)
938 var webResponse = (WebResponse)webResult.AsyncState;
939 var restRequest = tag.First;
940 var userState = tag.Third;
942 var m = new MemoryStream();
943 using (var stream = webResponse.GetResponseStream())
947 using (var reader = new StreamReader(stream))
949 while (reader.Peek() >= 0)
951 m.WriteByte((byte) reader.Read());
958 var restResponse = new RestResponse<T>
961 ContentType = webResponse.ContentType,
962 ContentLength = webResponse.ContentLength,
963 StatusCode = restRequest.ExpectStatusCode.HasValue
964 ? restRequest.ExpectStatusCode.Value
966 StatusDescription = restRequest.ExpectStatusDescription,
967 ResponseUri = webResponse.ResponseUri,
971 foreach (var key in webResponse.Headers.AllKeys)
973 restResponse.Headers.Add(key, webResponse.Headers[key]);
976 var deserializer = restRequest.Deserializer ?? Deserializer;
977 if (deserializer != null && !restResponse.Content.IsNullOrBlank())
979 restResponse.ContentEntity = deserializer.Deserialize<T>(restResponse);
982 TraceResponseWithMock(restResponse);
984 var parentResult = (WebQueryAsyncResult)result;
985 parentResult.AsyncState = restResponse;
986 parentResult.IsCompleted = true;
988 var callback = tag.Second;
989 if (callback != null)
991 callback.Invoke(restRequest, restResponse, userState);
993 parentResult.Signal();
997 private WebQueryAsyncResult CompleteWithMockWebResponse(
999 IAsyncResult webResult,
1000 Triplet<RestRequest, RestCallback, object> tag)
1002 var webResponse = (WebResponse)webResult.AsyncState;
1003 var restRequest = tag.First;
1004 var userState = tag.Third;
1006 var m = new MemoryStream();
1007 using (var stream = webResponse.GetResponseStream())
1011 using (var reader = new StreamReader(stream))
1013 while (reader.Peek() >= 0)
1015 m.WriteByte((byte) reader.Read());
1022 var restResponse = new RestResponse
1025 ContentType = webResponse.ContentType,
1026 ContentLength = webResponse.ContentLength,
1027 StatusCode = restRequest.ExpectStatusCode.HasValue
1028 ? restRequest.ExpectStatusCode.Value
1030 StatusDescription = restRequest.ExpectStatusDescription,
1031 ResponseUri = webResponse.ResponseUri,
1035 foreach (var key in webResponse.Headers.AllKeys)
1037 restResponse.Headers.Add(key, webResponse.Headers[key]);
1040 var deserializer = restRequest.Deserializer ?? Deserializer;
1041 if (deserializer != null && !restResponse.Content.IsNullOrBlank() && restRequest.ResponseEntityType != null)
1043 restResponse.ContentEntity = deserializer.Deserialize(restResponse, restRequest.ResponseEntityType);
1046 TraceResponseWithMock(restResponse);
1048 var parentResult = (WebQueryAsyncResult)result;
1049 parentResult.AsyncState = restResponse;
1050 parentResult.IsCompleted = true;
1052 var callback = tag.Second;
1053 if (callback != null)
1055 callback.Invoke(restRequest, restResponse, userState);
1057 parentResult.Signal();
1058 return parentResult;
1061 private void TraceResponseWithMock(RestResponseBase restResponse)
1069 Trace.WriteLine(string.Concat("RESPONSE: ", restResponse.StatusCode, " ", restResponse.StatusDescription));
1070 Trace.WriteLineIf(restResponse.Headers.AllKeys.Count() > 0, "HEADERS:");
1071 foreach (var trace in restResponse.Headers.AllKeys.Select(key => string.Concat("\t", key, ": ", restResponse.Headers[key])))
1073 Trace.WriteLine(trace);
1075 Trace.WriteLine(string.Concat("\r\n", restResponse.Content));
1080 // TODO BeginRequestImpl and BeginRequestImpl<T> have too much duplication
1081 private IAsyncResult BeginRequestImpl(RestRequest request,
1082 RestCallback callback,
1088 request = request ?? new RestRequest();
1091 // [DC]: Recursive call possible, only do this once
1092 var uri = request.BuildEndpoint(this);
1093 query = GetQueryFor(request, uri);
1094 SetQueryMeta(request, query);
1095 url = uri.ToString();
1098 if (RequestExpectsMock(request))
1100 url = BuildMockRequestUrl(request, query, url);
1103 var retryPolicy = GetRetryPolicy(request);
1104 bool inRetryScope = false;
1105 if (!isInternal && retryPolicy != null)
1107 _remainingRetries = retryPolicy.RetryCount;
1108 inRetryScope = true;
1111 Func<WebQueryAsyncResult> beginRequest;
1112 WebQueryAsyncResult asyncResult;
1114 var streamOptions = GetStreamOptions(request);
1115 if (streamOptions != null)
1118 query.KeepAlive = true;
1120 var duration = streamOptions.Duration.HasValue
1121 ? streamOptions.Duration.Value
1124 var resultCount = streamOptions.ResultsPerCallback.HasValue
1125 ? streamOptions.ResultsPerCallback.Value
1128 beginRequest = () => BeginRequestStreamFunction(
1129 request, query, url, callback, duration, resultCount, userState
1132 asyncResult = beginRequest.Invoke();
1137 = () => BeginRequestFunction(isInternal,
1144 asyncResult = beginRequest.Invoke();
1147 if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
1149 if (IsFirstIteration && request.IsFirstIteration)
1151 query.QueryResponse += (sender, args) =>
1153 var current = query.Result;
1155 if (retryPolicy != null)
1157 // [DC]: Query should already have exception applied
1158 var exception = query.Result.Exception;
1159 var retry = inRetryScope &&
1160 _remainingRetries > 0 &&
1161 ShouldRetry(retryPolicy, exception, current);
1165 UpdateRetryState(request);
1166 BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
1167 Interlocked.Decrement(ref _remainingRetries);
1168 if(_remainingRetries > 0)
1170 OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
1173 else if (inRetryScope)
1175 _remainingRetries = 0;
1177 current.TimesTried = GetIterationCount(request);
1179 else if (inRetryScope)
1181 _remainingRetries = 0;
1184 query.Result = current;
1186 if (_remainingRetries == 0)
1188 CompleteWithQuery(query, request, callback, asyncResult);
1192 UpdateRepeatingRequestState(request);
1199 private IAsyncResult BeginRequestImplDynamic(RestRequest request,
1200 RestCallback<dynamic> callback,
1206 request = request ?? new RestRequest();
1209 var uri = request.BuildEndpoint(this);
1210 query = GetQueryFor(request, uri);
1211 SetQueryMeta(request, query);
1212 url = uri.ToString();
1215 if (RequestExpectsMock(request))
1217 url = BuildMockRequestUrl(request, query, url);
1220 var retryPolicy = GetRetryPolicy(request);
1221 bool inRetryScope = false;
1222 if (!isInternal && retryPolicy != null)
1224 _remainingRetries = retryPolicy.RetryCount;
1225 inRetryScope = true;
1228 Func<WebQueryAsyncResult> beginRequest;
1229 WebQueryAsyncResult asyncResult;
1231 var streamOptions = GetStreamOptions(request);
1232 if (streamOptions != null)
1235 query.KeepAlive = true;
1238 var duration = streamOptions.Duration.HasValue
1239 ? streamOptions.Duration.Value
1242 var resultCount = streamOptions.ResultsPerCallback.HasValue
1243 ? streamOptions.ResultsPerCallback.Value
1246 beginRequest = () => BeginRequestStreamFunction(
1247 request, query, url, callback, duration, resultCount, userState
1250 asyncResult = beginRequest.Invoke();
1254 beginRequest = () => BeginRequestFunction(
1255 isInternal, request, query, url, callback, userState
1258 asyncResult = beginRequest.Invoke();
1260 if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
1262 if (IsFirstIteration && request.IsFirstIteration)
1264 query.QueryResponse += (sender, args) =>
1266 var current = query.Result;
1268 if (retryPolicy != null)
1270 // [DC]: Query should already have exception applied
1271 var exception = query.Result.Exception;
1272 var retry = inRetryScope &&
1273 _remainingRetries > 0 &&
1274 ShouldRetry(retryPolicy, exception, current);
1278 UpdateRetryState(request);
1279 BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
1280 Interlocked.Decrement(ref _remainingRetries);
1281 if (_remainingRetries > 0)
1283 OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
1286 else if (inRetryScope)
1288 _remainingRetries = 0;
1290 current.TimesTried = GetIterationCount(request);
1292 else if (inRetryScope)
1294 _remainingRetries = 0;
1297 query.Result = current;
1299 // [DC]: Callback is for a final result, not a retry
1300 if (_remainingRetries == 0)
1302 CompleteWithQueryDynamic(query, request, callback, asyncResult);
1306 UpdateRepeatingRequestState(request);
1312 private IAsyncResult BeginRequestImpl<T>(RestRequest request,
1313 RestCallback<T> callback,
1319 request = request ?? new RestRequest();
1322 var uri = request.BuildEndpoint(this);
1323 query = GetQueryFor(request, uri);
1324 SetQueryMeta(request, query);
1325 url = uri.ToString();
1328 if (RequestExpectsMock(request))
1330 url = BuildMockRequestUrl(request, query, url);
1333 var retryPolicy = GetRetryPolicy(request);
1334 bool inRetryScope = false;
1335 if (!isInternal && retryPolicy != null)
1337 _remainingRetries = retryPolicy.RetryCount;
1338 inRetryScope = true;
1341 Func<WebQueryAsyncResult> beginRequest;
1342 WebQueryAsyncResult asyncResult;
1344 var streamOptions = GetStreamOptions(request);
1345 if (streamOptions != null)
1348 query.KeepAlive = true;
1351 var duration = streamOptions.Duration.HasValue
1352 ? streamOptions.Duration.Value
1355 var resultCount = streamOptions.ResultsPerCallback.HasValue
1356 ? streamOptions.ResultsPerCallback.Value
1359 beginRequest = () => BeginRequestStreamFunction(
1360 request, query, url, callback, duration, resultCount, userState
1363 asyncResult = beginRequest.Invoke();
1367 beginRequest = () => BeginRequestFunction(
1368 isInternal, request, query, url, callback, userState
1371 asyncResult = beginRequest.Invoke();
1373 if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
1375 if (IsFirstIteration && request.IsFirstIteration)
1377 query.QueryResponse += (sender, args) =>
1379 var current = query.Result;
1381 if (retryPolicy != null)
1383 // [DC]: Query should already have exception applied
1384 var exception = query.Result.Exception;
1385 var retry = inRetryScope &&
1386 _remainingRetries > 0 &&
1387 ShouldRetry(retryPolicy, exception, current);
1391 UpdateRetryState(request);
1392 BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
1393 Interlocked.Decrement(ref _remainingRetries);
1394 if(_remainingRetries > 0)
1396 OnBeforeRetry(new RetryEventArgs { Client = this, Request = request });
1399 else if (inRetryScope)
1401 _remainingRetries = 0;
1403 current.TimesTried = GetIterationCount(request);
1405 else if (inRetryScope)
1407 _remainingRetries = 0;
1410 query.Result = current;
1412 // [DC]: Callback is for a final result, not a retry
1413 if (_remainingRetries == 0)
1415 CompleteWithQuery(query, request, callback, asyncResult);
1419 UpdateRepeatingRequestState(request);
1424 // TODO BeginRequest and BeginRequest<T> have too much duplication
1426 private void BeginRequestImpl(RestRequest request,
1427 RestCallback callback,
1433 request = request ?? new RestRequest();
1436 // [DC]: Recursive call possible, only do this once
1437 var uri = request.BuildEndpoint(this);
1438 query = GetQueryFor(request, uri);
1439 SetQueryMeta(request, query);
1440 url = uri.ToString();
1443 if (RequestExpectsMock(request))
1445 url = BuildMockRequestUrl(request, query, url);
1448 var retryPolicy = GetRetryPolicy(request);
1449 _remainingRetries = (retryPolicy != null
1450 ? retryPolicy.RetryCount
1453 Action beginRequest;
1455 var streamOptions = GetStreamOptions(request);
1456 if (streamOptions != null)
1459 query.KeepAlive = true;
1461 var duration = streamOptions.Duration.HasValue
1462 ? streamOptions.Duration.Value
1465 var resultCount = streamOptions.ResultsPerCallback.HasValue
1466 ? streamOptions.ResultsPerCallback.Value
1469 beginRequest = () => BeginRequestStreamFunction(
1470 request, query, url, callback, duration, resultCount, userState
1473 beginRequest.Invoke();
1477 beginRequest = ()=> BeginRequestFunction(isInternal,
1484 beginRequest.Invoke();
1487 if (isInternal || (request.TaskOptions == null || request.TaskOptions.RepeatInterval.TotalMilliseconds == 0))
1489 if (request.IsFirstIteration && IsFirstIteration)
1491 query.QueryResponse += (sender, args) => QueryResponseCallback(query,
1498 UpdateRepeatingRequestState(request);
1499 UpdateRetryState(request);
1503 private void BeginRequestImpl<T>(RestRequest request,
1504 RestCallback<T> callback,
1510 request = request ?? new RestRequest();
1513 var uri = request.BuildEndpoint(this);
1514 query = GetQueryFor(request, uri);
1515 SetQueryMeta(request, query);
1516 url = uri.ToString();
1519 if (RequestExpectsMock(request))
1521 url = BuildMockRequestUrl(request, query, url);
1524 var retryPolicy = GetRetryPolicy(request);
1525 _remainingRetries = (retryPolicy != null
1526 ? retryPolicy.RetryCount
1529 Action beginRequest;
1530 var streamOptions = GetStreamOptions(request);
1531 if (streamOptions != null)
1534 query.KeepAlive = true;
1537 var duration = streamOptions.Duration.HasValue
1538 ? streamOptions.Duration.Value
1541 var resultCount = streamOptions.ResultsPerCallback.HasValue
1542 ? streamOptions.ResultsPerCallback.Value
1545 beginRequest = () => BeginRequestStreamFunction(
1546 request, query, url, callback, duration, resultCount, userState
1549 beginRequest.Invoke();
1553 beginRequest = () => BeginRequestFunction(
1554 isInternal, request, query, url, callback, userState
1557 beginRequest.Invoke();
1559 if (IsFirstIteration && request.IsFirstIteration)
1561 query.QueryResponse += (sender, args) => QueryResponseCallback(query,
1568 UpdateRepeatingRequestState(request);
1569 UpdateRetryState(request);
1572 private void QueryResponseCallback(WebQuery query,
1573 RetryPolicy retryPolicy,
1574 RestRequest request,
1575 RestCallback callback,
1579 var current = query.Result;
1581 if (retryPolicy != null)
1583 // [DC]: Query should already have exception applied
1584 var exception = query.Result.Exception;
1585 var retry = _remainingRetries > 0 && ShouldRetry(retryPolicy, exception, current);
1589 BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
1590 Interlocked.Decrement(ref _remainingRetries);
1594 _remainingRetries = 0;
1596 current.TimesTried = GetIterationCount(request);
1600 _remainingRetries = 0;
1603 query.Result = current;
1605 // [DC]: Callback is for a final result, not a retry
1606 if (_remainingRetries == 0)
1608 CompleteWithQuery(query, request, callback);
1611 private void QueryResponseCallback<T>(WebQuery query,
1612 RetryPolicy retryPolicy,
1613 RestRequest request,
1614 RestCallback<T> callback,
1618 var current = query.Result;
1620 if (retryPolicy != null)
1622 // [DC]: Query should already have exception applied
1623 var exception = query.Result.Exception;
1624 var retry = _remainingRetries > 0 && ShouldRetry(retryPolicy, exception, current);
1628 BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
1629 Interlocked.Decrement(ref _remainingRetries);
1633 _remainingRetries = 0;
1635 current.TimesTried = GetIterationCount(request);
1640 _remainingRetries = 0;
1643 query.Result = current;
1645 // [DC]: Callback is for a final result, not a retry
1646 if (_remainingRetries == 0)
1648 CompleteWithQuery(query, request, callback);
1654 private WebQueryAsyncResult BeginRequestFunction(bool isInternal,
1655 RestRequest request,
1658 RestCallback callback,
1661 WebQueryAsyncResult result;
1664 if (!BeginRequestWithTask(request, callback, query, url, out result, userState))
1666 if (!BeginRequestWithCache(request, query, url, out result, userState))
1668 if (!BeginRequestMultiPart(request, query, url, out result, userState))
1671 result = query.RequestAsync(url, userState);
1679 result = query.RequestAsync(url, userState);
1682 result.Tag = new Triplet<RestRequest, RestCallback, object>
1692 private void BeginRequestFunction(bool isInternal,
1693 RestRequest request,
1696 RestCallback callback,
1701 if (!BeginRequestWithTask(request, callback, query, url, userState))
1703 if (!BeginRequestWithCache(request, query, url, userState))
1705 if (!BeginRequestMultiPart(request, query, url, userState))
1708 query.RequestAsync(url, userState);
1716 query.RequestAsync(url, userState);
1721 private void SignalTasks(RestRequest request, WebQueryAsyncResult result)
1723 // Recurring tasks are only signalled when cancelled
1724 // or when they reach their iteration limit
1725 lock (_timedTasksLock)
1727 if (!_tasks.ContainsKey(request))
1737 private void CompleteWithQueryDynamic(WebQuery query,
1738 RestRequest request,
1739 RestCallback<dynamic> callback,
1740 WebQueryAsyncResult result)
1742 var response = BuildResponseFromResultDynamic(request, query);
1744 CompleteWithQuery(request, query, callback, response, result);
1748 private void CompleteWithQuery<T>(WebQuery query,
1749 RestRequest request,
1750 RestCallback<T> callback,
1751 WebQueryAsyncResult result)
1753 var response = BuildResponseFromResult<T>(request, query);
1755 CompleteWithQuery(request, query, callback, response, result);
1758 private void CompleteWithQuery<T>(RestRequest request, WebQuery query, RestCallback<T> callback, RestResponse<T> response, WebQueryAsyncResult result)
1760 if (query.IsStreaming && callback != null)
1762 callback.Invoke(request, response, query.UserState);
1766 var wasStreaming = response.Content.Equals(EndStreamingContent);
1768 result.AsyncState = response;
1769 result.IsCompleted = true;
1770 if (callback != null && !wasStreaming)
1772 callback.Invoke(request, response, query.UserState);
1777 _streamQuery = null;
1780 SignalTasks(request, result);
1783 private void CompleteWithQuery(WebQuery query,
1784 RestRequest request,
1785 RestCallback callback,
1786 WebQueryAsyncResult result)
1788 var response = BuildResponseFromResult(request, query);
1789 if (query.IsStreaming && callback != null)
1791 callback.Invoke(request, response, query.UserState);
1795 var wasStreaming = response.Content.Equals(EndStreamingContent);
1797 result.AsyncState = response;
1798 result.IsCompleted = true;
1799 if (callback != null && !wasStreaming)
1801 callback.Invoke(request, response, query.UserState);
1806 _streamQuery = null;
1809 SignalTasks(request, result);
1812 private void CompleteWithQuery<T>(WebQuery query,
1813 RestRequest request,
1814 RestCallback<T> callback)
1816 var response = BuildResponseFromResult<T>(request, query);
1817 if (query.IsStreaming)
1822 var wasStreaming = response.Content.Equals("END STREAMING");
1824 if (callback != null && !wasStreaming)
1826 callback.Invoke(request, response, query.UserState);
1829 private void CompleteWithQuery(WebQuery query,
1830 RestRequest request,
1831 RestCallback callback)
1833 var response = BuildResponseFromResult(request, query);
1834 if (query.IsStreaming)
1839 var wasStreaming = response.Content.Equals("END STREAMING");
1841 if (callback != null && !wasStreaming)
1843 callback.Invoke(request, response, query.UserState);
1849 private WebQueryAsyncResult BeginRequestFunction<T>(bool isInternal,
1850 RestRequest request,
1853 RestCallback<T> callback,
1857 WebQueryAsyncResult result;
1860 if (!BeginRequestWithTask(request, callback, query, url, out result, userState))
1862 if (!BeginRequestWithCache(request, query, url, out result, userState))
1864 if (!BeginRequestMultiPart(request, query, url, out result, userState))
1867 result = query.RequestAsync(url, userState);
1875 result = query.RequestAsync(url, userState);
1878 result.Tag = new Triplet<RestRequest, RestCallback<T>, object>
1887 private void BeginRequestFunction<T>(bool isInternal,
1888 RestRequest request,
1891 RestCallback<T> callback,
1897 if (!BeginRequestWithTask(request, callback, query, url, userState))
1899 if (!BeginRequestWithCache(request, query, url, userState))
1901 if (!BeginRequestMultiPart(request, query, url, userState))
1904 query.RequestAsync(url, userState);
1912 query.RequestAsync(url, userState);
1916 private WebQueryAsyncResult BeginRequestStreamFunction<T>(RestRequest request,
1919 RestCallback<T> callback,
1921 int resultsPerCallback,
1924 var result = GetStreamResult(request, query, url, duration, resultsPerCallback);
1926 result.Tag = new Triplet<RestRequest, RestCallback<T>, object>
1935 private WebQueryAsyncResult BeginRequestStreamFunction(RestRequest request,
1938 RestCallback callback,
1940 int resultsPerCallback,
1943 var result = GetStreamResult(request, query, url, duration, resultsPerCallback);
1945 result.Tag = new Triplet<RestRequest, RestCallback, object>
1955 private WebQueryAsyncResult GetStreamResult(RestBase request,
1959 int resultsPerCallback)
1961 if (!request.Method.HasValue)
1963 request.Method = WebMethod.Get;
1966 WebQueryAsyncResult result;
1967 switch (request.Method)
1970 result = query.ExecuteStreamGetAsync(url, duration, resultsPerCallback);
1972 case WebMethod.Post:
1973 result = query.ExecuteStreamPostAsync(url, duration, resultsPerCallback);
1976 throw new NotSupportedException("Unsupported HTTP method declared for streaming.");
1979 _streamQuery = query;
1984 private void RegisterTimedTaskForRequest(RestRequest request, TimedTask task)
1986 lock (_timedTasksLock)
1988 if (_tasks.ContainsKey(request))
1990 throw new InvalidOperationException("Task already has a registered timed task");
1992 task.Stopped += (s, e) => UnregisterTimedTaskForRequest(request);
1993 _tasks.Add(request, task);
1997 private void UnregisterTimedTaskForRequest(RestRequest request)
1999 lock (_timedTasksLock)
2001 if (_tasks.ContainsKey(request))
2003 var task = _tasks[request];
2004 _tasks.Remove(request);
2011 private bool BeginRequestWithTask(RestRequest request,
2012 RestCallback callback,
2015 out WebQueryAsyncResult asyncResult,
2018 var taskOptions = GetTaskOptions(request);
2019 if (taskOptions == null)
2025 if (taskOptions.RepeatInterval <= TimeSpan.Zero)
2033 if (!taskOptions.GetType().IsGenericType)
2036 // Tasks without rate limiting
2037 task = new TimedTask(taskOptions.DueTime,
2038 taskOptions.RepeatInterval,
2039 taskOptions.RepeatTimes,
2040 taskOptions.ContinueOnError,
2041 skip => BeginRequestImpl(request,
2045 true /* isInternal */,
2053 // Tasks with rate limiting
2054 task = (TimedTask)BuildRateLimitingTask(request,
2063 RegisterTimedTaskForRequest(request, task);
2065 Action action = task.Start;
2067 var inner = action.BeginInvoke(ar => {/* No callback */}, null);
2069 asyncResult = new WebQueryAsyncResult { InnerResult = inner };
2070 task.AsyncResult = asyncResult;
2074 private bool BeginRequestWithTask<T>(RestRequest request,
2075 RestCallback<T> callback,
2078 out WebQueryAsyncResult asyncResult,
2081 var taskOptions = GetTaskOptions(request);
2082 if (taskOptions == null)
2088 if (taskOptions.RepeatInterval <= TimeSpan.Zero)
2096 if (!taskOptions.GetType().IsGenericType)
2099 // Tasks without rate limiting
2100 task = new TimedTask(taskOptions.DueTime,
2101 taskOptions.RepeatInterval,
2102 taskOptions.RepeatTimes,
2103 taskOptions.ContinueOnError,
2104 skip => BeginRequestImpl(request,
2108 true /* isInternal */,
2114 // Tasks with rate limiting
2115 task = (TimedTask)BuildRateLimitingTask(request,
2124 lock (_timedTasksLock)
2126 _tasks[request] = task;
2128 var action = new Action(task.Start);
2130 var inner = action.BeginInvoke(ar => { /* No callback */ }, null);
2131 asyncResult = new WebQueryAsyncResult { InnerResult = inner };
2132 task.AsyncResult = asyncResult;
2136 private bool BeginRequestWithTask(RestRequest request,
2137 RestCallback callback,
2142 var taskOptions = GetTaskOptions(request);
2143 if (taskOptions == null)
2148 if (taskOptions.RepeatInterval <= TimeSpan.Zero)
2154 if (!taskOptions.GetType().IsGenericType)
2156 // Tasks without rate limiting
2157 task = new TimedTask(taskOptions.DueTime,
2158 taskOptions.RepeatInterval,
2159 taskOptions.RepeatTimes,
2160 taskOptions.ContinueOnError,
2161 skip => BeginRequestImpl(request,
2165 true /* isInternal */,
2171 // Tasks with rate limiting
2172 task = (TimedTask)BuildRateLimitingTask(request,
2180 RegisterTimedTaskForRequest(request, task);
2182 var action = new Action(task.Start);
2187 private bool BeginRequestWithTask<T>(RestRequest request,
2188 RestCallback<T> callback,
2193 var taskOptions = GetTaskOptions(request);
2194 if (taskOptions == null)
2199 if (taskOptions.RepeatInterval <= TimeSpan.Zero)
2205 if (!taskOptions.GetType().IsGenericType)
2207 // Tasks without rate limiting
2208 task = new TimedTask(taskOptions.DueTime,
2209 taskOptions.RepeatInterval,
2210 taskOptions.RepeatTimes,
2211 taskOptions.ContinueOnError,
2212 skip => BeginRequestImpl(request,
2216 true /* isInternal */,
2221 // Tasks with rate limiting
2222 task = (TimedTask)BuildRateLimitingTask(request,
2230 lock (_timedTasksLock)
2232 _tasks[request] = task;
2235 var action = new Action(task.Start);
2242 private object BuildRateLimitingTask(RestRequest request, ITaskOptions taskOptions, RestCallback callback, WebQuery query, string url, object userState)
2244 var taskAction = new Action<bool>(skip =>
2248 BeginRequestImpl(request, callback, query, url, true /* isInternal */, userState);
2253 new RestResponse { SkippedDueToRateLimitingRule = true },
2258 return BuildRateLimitingTaskImpl(taskOptions, taskAction);
2261 private object BuildRateLimitingTask<T>(RestRequest request,
2262 ITaskOptions taskOptions,
2263 RestCallback<T> callback,
2268 var taskAction = new Action<bool>(skip => BeginRequestImpl(request,
2272 true /* isInternal */,
2276 return BuildRateLimitingTaskImpl(taskOptions, taskAction);
2279 private static object BuildRateLimitingTaskImpl(ITaskOptions taskOptions,
2280 Action<bool> taskAction)
2282 var innerType = taskOptions.GetDeclaredTypeForGeneric(typeof(ITaskOptions<>));
2283 var rateType = typeof(RateLimitingRule<>).MakeGenericType(innerType);
2284 var taskType = typeof(TimedTask<>).MakeGenericType(innerType);
2285 var rateLimitingType = (RateLimitType)taskOptions.GetValue("RateLimitType");
2288 var getRateLimitStatus = taskOptions.GetValue("GetRateLimitStatus");
2289 switch (rateLimitingType)
2291 case RateLimitType.ByPercent:
2292 var rateLimitingPercent = taskOptions.GetValue("RateLimitPercent");
2293 taskRule = getRateLimitStatus != null
2294 ? Activator.CreateInstance(rateType, getRateLimitStatus, rateLimitingPercent)
2295 : Activator.CreateInstance(rateType, rateLimitingPercent);
2297 case RateLimitType.ByPredicate:
2298 var rateLimitingPredicate = taskOptions.GetValue("RateLimitingPredicate");
2299 taskRule = getRateLimitStatus != null
2300 ? Activator.CreateInstance(rateType, getRateLimitStatus, rateLimitingPredicate)
2301 : Activator.CreateInstance(rateType, rateLimitingPredicate);
2304 throw new ArgumentOutOfRangeException();
2307 return Activator.CreateInstance(taskType,
2308 taskOptions.DueTime,
2309 taskOptions.RepeatInterval,
2310 taskOptions.RepeatTimes,
2311 taskOptions.ContinueOnError,
2318 private bool BeginRequestMultiPart(RestBase request, WebQuery query, string url, out WebQueryAsyncResult result, object userState)
2320 var parameters = GetPostParameters(request);
2321 if (parameters == null || parameters.Count() == 0)
2327 // [DC]: Default to POST if no method provided
2328 query.Method = query.Method != WebMethod.Post && Method != WebMethod.Put ? WebMethod.Post : query.Method;
2329 result = query.RequestAsync(url, parameters, userState);
2333 private bool BeginRequestMultiPart(RestBase request, WebQuery query, string url, object userState)
2335 var parameters = GetPostParameters(request);
2336 if (parameters == null || parameters.Count() == 0)
2341 // [DC]: Default to POST if no method provided
2342 query.Method = query.Method != WebMethod.Post && Method != WebMethod.Put ? WebMethod.Post : query.Method;
2343 query.RequestAsync(url, parameters, userState);
2349 private bool BeginRequestWithCache(RestBase request,
2352 out WebQueryAsyncResult result,
2355 var cache = GetCache(request);
2362 var options = GetCacheOptions(request);
2363 if (options == null)
2369 // [DC]: This is currently prefixed to the full URL
2370 var function = GetCacheKeyFunction(request);
2371 var key = function != null ? function.Invoke() : "";
2373 switch (options.Mode)
2375 case CacheMode.NoExpiration:
2376 result = query.RequestAsync(url, key, cache, userState);
2378 case CacheMode.AbsoluteExpiration:
2379 var expiry = options.Duration.FromNow();
2380 result = query.RequestAsync(url, key, cache, expiry, userState);
2382 case CacheMode.SlidingExpiration:
2383 result = query.RequestAsync(url, key, cache, options.Duration, userState);
2386 throw new NotSupportedException("Unknown CacheMode");
2392 private bool BeginRequestWithCache(RestBase request,
2397 var cache = GetCache(request);
2403 var options = GetCacheOptions(request);
2404 if (options == null)
2409 // [DC]: This is currently prefixed to the full URL
2410 var function = GetCacheKeyFunction(request);
2411 var key = function != null ? function.Invoke() : "";
2413 switch (options.Mode)
2415 case CacheMode.NoExpiration:
2416 query.RequestAsync(url, key, cache, userState);
2418 case CacheMode.AbsoluteExpiration:
2419 var expiry = options.Duration.FromNow();
2420 query.RequestAsync(url, key, cache, expiry, userState);
2422 case CacheMode.SlidingExpiration:
2423 query.RequestAsync(url, key, cache, options.Duration, userState);
2426 throw new NotSupportedException("Unknown CacheMode");
2433 private RestResponse BuildResponseFromResult(RestRequest request, WebQuery query)
2435 request = request ?? new RestRequest();
2436 var result = query.Result;
2437 var response = BuildBaseResponse(result);
2439 DeserializeEntityBody(request, response);
2440 response.Tag = GetTag(request);
2445 private RestResponse<T> BuildResponseFromResult<T>(RestRequest request, WebQuery query)
2447 request = request ?? new RestRequest();
2448 var result = query.Result;
2449 var response = BuildBaseResponse<T>(result);
2451 DeserializeEntityBody(request, response);
2452 response.Tag = GetTag(request);
2458 private RestResponse<dynamic> BuildResponseFromResultDynamic(RestRequest request, WebQuery query)
2460 request = request ?? new RestRequest();
2461 var result = query.Result;
2462 var response = BuildBaseResponse<dynamic>(result);
2464 DeserializeEntityBodyDynamic(request, response);
2465 response.Tag = GetTag(request);
2471 private static readonly Func<RestResponseBase, WebQueryResult, RestResponseBase> _baseSetter =
2472 (response, result) =>
2474 response.ContentStream = result.ContentStream;
2475 response.InnerResponse = result.WebResponse;
2476 response.InnerException = result.Exception;
2477 response.RequestDate = result.RequestDate;
2478 response.RequestUri = result.RequestUri;
2479 response.RequestMethod = result.RequestHttpMethod;
2480 response.RequestKeptAlive = result.RequestKeptAlive;
2481 response.ResponseDate = result.ResponseDate;
2482 response.ResponseUri = result.ResponseUri;
2483 response.StatusCode = (HttpStatusCode)result.ResponseHttpStatusCode;
2484 response.StatusDescription = result.ResponseHttpStatusDescription;
2485 response.ContentType = result.ResponseType;
2486 response.ContentLength = result.ResponseLength;
2487 response.IsMock = result.IsMock;
2488 response.TimedOut = result.TimedOut;
2489 response.TimesTried = result.TimesTried;
2490 if (result.WebResponse == null)
2492 // [DC] WebResponse could be null, i.e. when streaming
2496 response.Headers = result.WebResponse.Headers;
2498 response.Headers = new NameValueCollection();
2499 foreach(var key in result.WebResponse.Headers.AllKeys)
2501 response.Headers.Add(key, result.WebResponse.Headers[key]);
2505 #if !SILVERLIGHT && !NETCF
2506 if(result.WebResponse is HttpWebResponse)
2508 var cookies = (result.WebResponse as HttpWebResponse).Cookies;
2511 foreach (Cookie cookie in cookies)
2513 response.Cookies.Add(cookie.Name, cookie.Value);
2522 private static RestResponse BuildBaseResponse(WebQueryResult result)
2524 var response = new RestResponse();
2526 _baseSetter.Invoke(response, result);
2531 private static RestResponse<T> BuildBaseResponse<T>(WebQueryResult result)
2533 var response = new RestResponse<T>();
2535 _baseSetter.Invoke(response, result);
2540 private bool ShouldDeserializeEntityBody(RestRequest request, RestResponseBase response, out IDeserializer deserializer)
2542 deserializer = request.Deserializer ?? Deserializer;
2543 if (deserializer == null || response.ContentStream == null || string.IsNullOrEmpty(response.ContentType))
2547 if (response.InnerException != null)
2549 Type errorResponseEntityType;
2550 var getErrorResponseEntityType = request.GetErrorResponseEntityType ?? GetErrorResponseEntityType;
2551 if (getErrorResponseEntityType != null && (errorResponseEntityType = getErrorResponseEntityType(request, response)) != null)
2553 response.ErrorContentEntity = deserializer.Deserialize(response, errorResponseEntityType);
2561 private void DeserializeEntityBody(RestRequest request, RestResponse response)
2563 IDeserializer deserializer;
2564 if (ShouldDeserializeEntityBody(request, response, out deserializer) && request.ResponseEntityType != null)
2566 response.ContentEntity = deserializer.Deserialize(response, request.ResponseEntityType);
2570 private void DeserializeEntityBody<T>(RestRequest request, RestResponse<T> response)
2572 IDeserializer deserializer;
2573 if (ShouldDeserializeEntityBody(request, response, out deserializer))
2575 response.ContentEntity = deserializer.Deserialize<T>(response);
2580 private void DeserializeEntityBodyDynamic(RestRequest request, RestResponse<dynamic> response)
2582 IDeserializer deserializer;
2583 if (ShouldDeserializeEntityBody(request, response, out deserializer))
2585 response.ContentEntity = deserializer.DeserializeDynamic(response);
2590 private void SetQueryMeta(RestRequest request, WebQuery query)
2592 // Fill query collections with found value pairs
2593 CoalesceWebPairsIntoCollection(query.Parameters, Parameters, request.Parameters);
2594 CoalesceWebPairsIntoCollection(query.Cookies, Cookies, request.Cookies);
2596 query.Headers.AddRange(Headers);
2597 query.Headers.AddRange(request.Headers);
2599 // [DC]: These properties are trumped by request over client
2600 query.UserAgent = GetUserAgent(request);
2601 query.Method = GetWebMethod(request);
2602 query.Proxy = GetProxy(request);
2603 query.RequestTimeout = GetTimeout(request);
2604 query.DecompressionMethods = GetDecompressionMethods(request);
2605 query.PostContent = GetPostContent(request);
2606 query.Encoding = GetEncoding(request);
2609 query.FollowRedirects = GetFollowRedirects(request);
2611 SerializeEntityBody(query, request);
2614 // [DC]: Trump duplicates by request over client over info values
2615 private static void CoalesceWebPairsIntoCollection(WebPairCollection target, params IEnumerable<WebPair>[] values)
2617 var parameters = new WebPairCollection(values.SelectMany(value => value));
2619 foreach (var pair in parameters)
2621 if(target[pair.Name] == null)
2628 private void SerializeEntityBody(WebQuery query, RestRequest request)
2630 var serializer = GetSerializer(request);
2631 if (serializer == null)
2633 // No suitable serializer for entity
2637 if (request.Entity == null || request.RequestEntityType == null)
2639 // Not enough information to serialize
2643 var entityBody = serializer.Serialize(request.Entity, request.RequestEntityType);
2644 query.Entity = !entityBody.IsNullOrBlank()
2647 Content = entityBody,
2648 ContentEncoding = serializer.ContentEncoding,
2649 ContentType = serializer.ContentType
2654 private WebEntity SerializeExpectEntity(RestRequest request)
2656 var serializer = GetSerializer(request);
2657 if (serializer == null || request.ExpectEntity == null)
2659 // No suitable serializer or entity
2663 var entityBody = serializer.Serialize(request.ExpectEntity, request.RequestEntityType);
2664 var entity = !entityBody.IsNullOrBlank()
2667 Content = entityBody,
2668 ContentEncoding = serializer.ContentEncoding,
2669 ContentType = serializer.ContentType
2674 public WebQuery GetQueryFor(RestBase request, Uri uri)
2676 var method = GetWebMethod(request);
2677 var credentials = GetWebCredentials(request);
2678 var info = GetInfo(request);
2679 var traceEnabled = GetTraceEnabled(request);
2681 // [DC]: UserAgent is set via Info
2682 // [DC]: Request credentials trump client credentials
2683 var query = credentials != null
2684 ? credentials.GetQueryFor(uri.ToString(), request, info, method, traceEnabled)
2685 : new BasicAuthWebQuery(info, traceEnabled);
2687 query.PostProgress += QueryPostProgress;
2690 query.HasElevatedPermissions = HasElevatedPermissions;
2691 query.SilverlightAcceptEncodingHeader = SilverlightAcceptEncodingHeader;
2692 query.SilverlightUserAgentHeader = SilverlightUserAgentHeader;
2697 private void QueryPostProgress(object sender, PostProgressEventArgs e)
2699 var args = new FileProgressEventArgs
2701 FileName = e.FileName,
2702 BytesWritten = e.BytesWritten,
2703 TotalBytes = e.TotalBytes
2705 OnFileProgress(args);
2708 public void CancelStreaming()
2710 lock (_streamingLock)
2712 if (_streamQuery != null)
2714 _streamQuery.IsStreaming = false;
2719 public void CancelPeriodicTasks()
2721 lock (_timedTasksLock)
2723 // Copy to a new list, since canceling
2724 // the task removes it from the _tasks
2725 // list, the enumeration will throw
2726 var toCancel = new List<TimedTask>();
2727 toCancel.AddRange(_tasks.Values);
2728 toCancel.ForEach(t => t.Stop());
2732 public int GetIterationCount(RestRequest request)
2734 var retryState = request.RetryState ?? RetryState;
2735 var taskState = request.TaskState ?? TaskState;
2736 if (retryState != null)
2738 return retryState.RepeatCount;
2740 if (taskState != null)
2742 return taskState.RepeatCount;