// flag below because it's a *pain* to break inside this routine unless it was intended. // we want the exceptions from here to considered the root for the debugger to land. /// <summary> /// Executes a JSON based REST rpc call /// </summary> /// <param name="baseUrl">The url to use</param> /// <param name="args">Arguments to append to the url, represented as a simplified json object (only holds scalar values)</param> /// <param name="payloadJson">The JSON to send as part of the request body</param> /// <param name="timestampField">If specificed, indicates a field to insert a timestamp into. This timestamp represents the time the object was last fetched (either from the file cache or from the server)</param> /// <param name="httpMethod">Set this to use a custom HTTP method (like DELETE)</param> /// <param name="fixupResponse">An optional custom routine that can massage the JSON returned into a more acceptable form. This is useful if the data from the server needs to be adjusted prior to anything else.</param> /// <param name="fixupError">An optional custom routine that can massage the JSON error object returned into a more acceptable form. This is useful if the error from the server needs to be adjusted prior to anything else. You may need to specify this to get the <see cref="JsonRpcException" /> to work properly.</param> /// <param name="cache">Indicates whether or not a file cache should be used for requests. The in memory cache is only on a per-thread basis. The file cache stores by URL and is global. The cache is very aggressive.</param> /// <returns>The JSON returned in the response body.</returns> /// <remarks>Exceptions are expected to have JSON in the response body. This JSON is used as the data for the exception. The exception thrown currently uses a simple heuristic to figure out what the relevant fields are. Usually however, you'll get the data using the Json property of it.</remarks> //[DebuggerNonUserCode] public static object Invoke( string baseUrl, IDictionary <string, object> args = null, object payloadJson = null, string timestampField = null, string httpMethod = null, Func <object, object> fixupResponse = null, Func <object, object> fixupError = null, JsonRpcCacheLevel cache = JsonRpcCacheLevel.Conservative) { HttpWebRequest wreq = null; HttpWebResponse wrsp = null; var url = GetInvocationUrl(baseUrl, args); wreq = WebRequest.Create(url) as HttpWebRequest; wreq.KeepAlive = true; wreq.Pipelined = true; wreq.AllowAutoRedirect = true; RequestCacheLevel cp = RequestCacheLevel.Default; switch (cache) { case JsonRpcCacheLevel.None: cp = RequestCacheLevel.NoCacheNoStore; break; case JsonRpcCacheLevel.Conservative: cp = RequestCacheLevel.Revalidate; break; case JsonRpcCacheLevel.Aggressive: cp = RequestCacheLevel.CacheIfAvailable; break; } wreq.CachePolicy = new RequestCachePolicy(cp); if (null != payloadJson) { if (string.IsNullOrEmpty(httpMethod)) { wreq.Method = "POST"; } else { wreq.Method = httpMethod; } wreq.ContentType = "application/json"; using (var sw = new StreamWriter(wreq.GetRequestStream())) { JsonObject.WriteTo(payloadJson, sw, null); sw.Flush(); } } else if (string.IsNullOrEmpty(httpMethod)) { wreq.Method = "GET"; } else { wreq.Method = httpMethod; } try { wrsp = wreq.GetResponse() as HttpWebResponse; if (wrsp.StatusCode != HttpStatusCode.NoContent) { using (var reader = JsonTextReader.CreateFrom(new StreamReader(wrsp.GetResponseStream()))) { object data = null; try { data = reader.ParseSubtree(); } catch (ExpectingException eex) { var ex = new JsonObject(); ex.Add("status_code", -39); ex.Add("status_message", "Malformed or empty JSON data returned: " + eex.Message); ex.Add("http_status", (int)wrsp.StatusCode); ex.Add("http_status_message", wrsp.StatusDescription); throw new JsonRpcException(ex); } if (null != fixupResponse) { data = fixupResponse(data); } if (!string.IsNullOrEmpty(timestampField)) { var d = data as IDictionary <string, object>; if (null != d) { DateTime dt = DateTime.UtcNow; d.Add(timestampField, dt.ToString("O")); } } return(data); } } else { return(null); } } catch (Exception ex) { var wex = ex as WebException; if (null != wex) { if (null == wrsp) { wrsp = wex.Response as HttpWebResponse; } if (null != wrsp) { using (var reader = JsonTextReader.CreateFrom(new StreamReader(wrsp.GetResponseStream()))) { object data = null; try { data = reader.ParseSubtree(); } catch (ExpectingException eex) { var jex = new JsonObject(); jex.Add("status_code", -39); jex.Add("status_message", "Malformed or empty JSON data returned: " + eex.Message); jex.Add("http_status", (int)wrsp.StatusCode); jex.Add("http_status_message", wrsp.StatusDescription); data = jex; } if (null != fixupError) { data = fixupError(data); } var d = data as IDictionary <string, object>; if (!string.IsNullOrEmpty(timestampField)) { if (null != d) { d.Add(timestampField, DateTime.UtcNow.ToString("O")); } } if (null != d) { throw new JsonRpcException(d); } } } } throw; } }