コード例 #1
0
ファイル: Test.cs プロジェクト: yaozd/JSON-RPC.NET
            public JsonRpcException PostProcess(JsonRequest rpc, JsonResponse response, object context)
            {
                run++;

                this.rpc = rpc;
                this.response = response;
                this.context = context;

                if (changeResponse_)
                {
                    return new JsonRpcException(-123, "Test error", null);
                }
                return null;
            }
コード例 #2
0
        private static void AsyncProcessInternal(string sessionId, string jsonRpc, object jsonRpcContext, Action<string> callback)
        {
            Handler handler = Handler.GetSessionHandler(sessionId);

            try
            {
                Tuple<JsonRequest>[] batch = null;
                if (isSingleRpc(jsonRpc))
                {
                    batch = new[] { Tuple.Create(JsonConvert.DeserializeObject<JsonRequest>(jsonRpc)) };
                }
                else
                {
                    batch = JsonConvert.DeserializeObject<JsonRequest[]>(jsonRpc)
                            .Select(request => new Tuple<JsonRequest>(request))
                            .ToArray();
                }

                if (batch.Length == 0)
                {
                    callback.Invoke(Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse
                    {
                        Error = handler.ProcessParseException(jsonRpc,
                            new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty."))
                    }));
                }

                foreach (var tuple in batch)
                {
                    JsonRequest jsonRequest = tuple.Item1;
                    JsonResponse jsonResponse = new JsonResponse();

                    if (jsonRequest == null)
                    {
                        jsonResponse.Error = handler.ProcessParseException(jsonRpc,
                            new JsonRpcException(-32700, "Parse error",
                                "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."));
                    }
                    else
                    {
                        jsonResponse.Id = jsonRequest.Id;

                        if (jsonRequest.Method == null)
                        {
                            jsonResponse.Error = handler.ProcessParseException(jsonRpc,
                                new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                        }
                        else
                        {
                            handler.Handle(jsonRequest, jsonRpcContext, 
                                delegate(JsonResponse a) 
                                {
                                    a.Id = jsonRequest.Id;
                                    if (a.Id != null || a.Error != null)
                                    {                                       
                                        callback.Invoke(JsonConvert.SerializeObject(a));
                                    }
                                }
                            );
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                callback.Invoke(Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse
                {
                    Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(-32700, "Parse error", ex))
                }));
            }
        }
コード例 #3
0
 private static string[] responseToStringArray(JsonResponse response)
 {
     string data = response.Result.ToString();
     data = data.Replace("\r\n", "");
     data = data.Replace("\"", "");
     data = data.Replace(" ", "");
     string[] array = data.Split(new char[] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
     return array;
 }
コード例 #4
0
        private JsonResponse PostProcess(Action <JsonResponse> callback, JsonRequest request, JsonResponse response, object context)
        {
            if (externalPostProcessingHandler != null)
            {
                JsonRpcException exception = externalPostProcessingHandler(request, response, context);
                if (exception != null)
                {
                    response = new JsonResponse()
                    {
                        Error = exception
                    };
                }
            }

            if (callback != null)
            {
                callback.Invoke(response);
            }

            return(response);
        }
コード例 #5
0
        private static void AsyncProcessInternal(string sessionId, string jsonRpc, object jsonRpcContext, Action <string> callback)
        {
            Handler handler = Handler.GetSessionHandler(sessionId);

            Tuple <JsonRequest>[] batch = null;
            if (isSingleRpc(jsonRpc))
            {
                batch = new[] { Tuple.Create(JsonConvert.DeserializeObject <JsonRequest>(jsonRpc)) };
            }
            else
            {
                batch = JsonConvert.DeserializeObject <JsonRequest[]>(jsonRpc)
                        .Select(request => new Tuple <JsonRequest>(request))
                        .ToArray();
            }

            if (batch.Length == 0)
            {
                callback.Invoke(JsonConvert.SerializeObject(new JsonResponse
                {
                    Error = handler.ProcessParseException(jsonRpc,
                                                          new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty."))
                }));
            }

            foreach (var tuple in batch)
            {
                JsonRequest  jsonRequest  = tuple.Item1;
                JsonResponse jsonResponse = new JsonResponse();

                if (jsonRequest == null)
                {
                    jsonResponse.Error = handler.ProcessParseException(jsonRpc,
                                                                       new JsonRpcException(-32700, "Parse error",
                                                                                            "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."));
                }
                else
                {
                    jsonResponse.Id = jsonRequest.Id;

                    if (jsonRequest.Method == null)
                    {
                        jsonResponse.Error = handler.ProcessParseException(jsonRpc,
                                                                           new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                    }
                    else
                    {
                        handler.Handle(jsonRequest, jsonRpcContext,
                                       delegate(JsonResponse a)
                        {
                            a.Id = jsonRequest.Id;
                            if (a.Id != null || a.Error != null)
                            {
                                callback.Invoke(JsonConvert.SerializeObject(a));
                            }
                        }
                                       );
                    }
                }
            }
        }
コード例 #6
0
ファイル: client.cs プロジェクト: zhaxg/JSON-RPC.NET
        public IObservable <JsonResponse <T> > Invoke <T>(JsonRequest jsonRpc, IScheduler scheduler)
        {
            var subj = new Subject <JsonResponse <T> >();

            int myId;

            lock (idLock)
            {
                myId = ++id;
            }
            jsonRpc.Id = myId.ToString();

            WebRequest req = null;

            try
            {
                req             = HttpWebRequest.CreateHttp(new Uri(ServiceEndpoint + "?callid=" + myId.ToString()));
                req.Method      = "Post";
                req.ContentType = "application/json-rpc";
            }
            catch (Exception ex)
            {
                return(Observable.Throw <JsonResponse <T> >(ex));
            }

            var ar = req.BeginGetRequestStream(new AsyncCallback((iar) =>
            {
                HttpWebRequest request = null;

                try
                {
                    request       = (HttpWebRequest)iar.AsyncState;
                    var json      = Newtonsoft.Json.JsonConvert.SerializeObject(jsonRpc);
                    var reqStream = req.EndGetRequestStream(iar);
                    using (var stream = new StreamWriter(reqStream))
                    {
                        stream.Write(json);
                        stream.Flush();
                        stream.Close();
                    }
                }
                catch (Exception ex)
                {
                    subj.OnError(ex);
                }

                var rar = req.BeginGetResponse(new AsyncCallback((riar) =>
                {
                    JsonResponse <T> rjson = null;
                    string sstream         = "";
                    try
                    {
                        var request1   = (HttpWebRequest)riar.AsyncState;
                        var resp       = (HttpWebResponse)request1.EndGetResponse(riar);
                        var respStream = resp.GetResponseStream();
                        using (var rstream = new StreamReader(CopyAndClose(respStream)))
                        {
                            sstream = rstream.ReadToEnd();
                        }

                        rjson = Newtonsoft.Json.JsonConvert.DeserializeObject <JsonResponse <T> >(sstream);
                    }
                    catch (Exception ex)
                    {
                        subj.OnError(ex);
                        return;
                    }

                    try
                    {
                        if (rjson == null)
                        {
                            JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(sstream) as JObject;
                            subj.OnError(new Exception(jo["Error"].ToString()));
                            return;
                        }
                    }
                    catch (Exception)
                    { }

                    subj.OnNext(rjson);
                    subj.OnCompleted();
                }), request);
            }), req);

            return(subj);
        }
コード例 #7
0
        /// <summary>
        /// Invokes a method to handle a JsonRpc request.
        /// </summary>
        /// <param name="Rpc">JsonRpc Request to be processed</param>
        /// <param name="RpcContext">Optional context that will be available from within the jsonRpcMethod.</param>
        /// <returns></returns>
        public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null, Action <JsonResponse> callback = null)
        {
            AddRpcContext(RpcContext);

            var preProcessingException = PreProcess(Rpc, RpcContext);

            if (preProcessingException != null)
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = preProcessingException,
                    Id    = Rpc.Id
                };
                //callback is called - if it is empty then nothing will be done
                //return response always- if callback is empty or not
                return(PostProcess(callback, Rpc, response, RpcContext));
            }

            SMDService metadata     = null;
            Delegate   handle       = null;
            var        haveDelegate = this.Handlers.TryGetValue(Rpc.Method, out handle);
            var        haveMetadata = this.MetaData.Services.TryGetValue(Rpc.Method, out metadata);

            if (haveDelegate == false || haveMetadata == false || metadata == null || handle == null)
            {
                JsonResponse response = new JsonResponse()
                {
                    Result = null,
                    Error  = new JsonRpcException(-32601, "Method not found", "The method does not exist / is not available."),
                    Id     = Rpc.Id
                };
                return(PostProcess(callback, Rpc, response, RpcContext));
            }

            bool isJObject = Rpc.Params is JObject;
            bool isJArray  = Rpc.Params is JArray;

            object[] parameters          = null;
            bool     expectsRefException = false;
            var      metaDataParamCount  = metadata.parameters.Count(x => x != null);

            var getCount = Rpc.Params as ICollection;
            var loopCt   = 0;

            if (getCount != null)
            {
                loopCt = getCount.Count;
            }

            var paramCount = loopCt;

            if (paramCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount - 1].ObjectType.Name.Contains(typeof(JsonRpcException).Name))
            {
                paramCount++;
                expectsRefException = true;
            }
            parameters = new object[metaDataParamCount];

            if (isJArray)
            {
                var jarr = ((JArray)Rpc.Params);
                //var loopCt = jarr.Count;
                //var pCount = loopCt;
                //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException))
                //    pCount++;
                //parameters = new object[pCount];
                for (int i = 0; i < loopCt; i++)
                {
                    parameters[i] = CleanUpParameter(jarr[i], metadata.parameters[i]);
                }
            }
            else if (isJObject)
            {
                var jo = Rpc.Params as JObject;
                //var loopCt = jo.Count;
                //var pCount = loopCt;
                //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException))
                //    pCount++;
                //parameters = new object[pCount];
                var asDict = jo as IDictionary <string, JToken>;
                for (int i = 0; i < loopCt && i < metadata.parameters.Length; i++)
                {
                    if (asDict.ContainsKey(metadata.parameters[i].Name) == false)
                    {
                        JsonResponse response = new JsonResponse()
                        {
                            Error = ProcessException(Rpc,
                                                     new JsonRpcException(-32602,
                                                                          "Invalid params",
                                                                          string.Format("Named parameter '{0}' was not present.",
                                                                                        metadata.parameters[i].Name)
                                                                          )),
                            Id = Rpc.Id
                        };
                        return(PostProcess(callback, Rpc, response, RpcContext));
                    }
                    parameters[i] = CleanUpParameter(jo[metadata.parameters[i].Name], metadata.parameters[i]);
                }
            }
            else if (Rpc.Params is IDictionary)
            {
                var dic = Rpc.Params as IDictionary;
                for (int i = 0; i < metadata.parameters.Length; i++)
                {
                    if (dic.Contains(metadata.parameters[i].Name))
                    {
                        if (dic[metadata.parameters[i].Name] is JObject)
                        {
                            parameters[i] = CleanUpParameter(dic[metadata.parameters[i].Name], metadata.parameters[i]);
                        }
                        else
                        {
                            parameters[i] = dic[metadata.parameters[i].Name].ConvertTo(metadata.parameters[i].ObjectType);
                        }
                    }
                }
            }

            // Optional Parameter support
            // check if we still miss parameters compared to metadata which may include optional parameters.
            // if the rpc-call didn't supply a value for an optional parameter, we should be assinging the default value of it.
            if (parameters.Length < metaDataParamCount && metadata.defaultValues.Length > 0)                   // rpc call didn't set values for all optional parameters, so we need to assign the default values for them.
            {
                var suppliedParamsCount = parameters.Length;                                                   // the index we should start storing default values of optional parameters.
                var missingParamsCount  = metaDataParamCount - parameters.Length;                              // the amount of optional parameters without a value set by rpc-call.
                Array.Resize(ref parameters, parameters.Length + missingParamsCount);                          // resize the array to include all optional parameters.

                for (int paramIndex = parameters.Length - 1, defaultIndex = metadata.defaultValues.Length - 1; // fill missing parameters from the back
                     paramIndex >= suppliedParamsCount && defaultIndex >= 0;                                   // to don't overwrite supplied ones.
                     paramIndex--, defaultIndex--)
                {
                    parameters[paramIndex] = metadata.defaultValues[defaultIndex].Value;
                }

                if (missingParamsCount > metadata.defaultValues.Length)
                {
                    JsonResponse response = new JsonResponse
                    {
                        Error = ProcessException(Rpc,
                                                 new JsonRpcException(-32602,
                                                                      "Invalid params",
                                                                      string.Format(
                                                                          "Number of default parameters {0} not sufficient to fill all missing parameters {1}",
                                                                          metadata.defaultValues.Length, missingParamsCount)
                                                                      )),
                        Id = Rpc.Id
                    };
                    return(PostProcess(callback, Rpc, response, RpcContext));
                }
            }

            if (parameters.Length != metaDataParamCount)
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = ProcessException(Rpc,
                                             new JsonRpcException(-32602,
                                                                  "Invalid params",
                                                                  string.Format("Expecting {0} parameters, and received {1}",
                                                                                metadata.parameters.Length,
                                                                                parameters.Length)
                                                                  )),
                    Id = Rpc.Id
                };
                return(PostProcess(callback, Rpc, response, RpcContext));
            }

            //try
            //{
            //callback is stored to thread's local storage in order to get it directly from concrete JsonRpcService method implementation
            //where callback is just returned from method
            Thread.SetData(Thread.GetNamedDataSlot(THREAD_CALLBACK_SLOT_NAME), callback);


            var results = handle.DynamicInvoke(parameters);

            var last = parameters.LastOrDefault();
            JsonRpcException contextException;

            if (Task.CurrentId.HasValue && RpcExceptions.TryRemove(Task.CurrentId.Value, out contextException))
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = ProcessException(Rpc, contextException), Id = Rpc.Id
                };
                return(PostProcess(callback, Rpc, response, RpcContext));
            }
            if (expectsRefException && last != null && last is JsonRpcException)
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = ProcessException(Rpc, last as JsonRpcException), Id = Rpc.Id
                };
                return(PostProcess(callback, Rpc, response, RpcContext));
            }
            //return response, if callback is set (method is asynchronous) - result could be empty string and future result operations
            //will be processed in the callback
            return(PostProcess(null, Rpc, new JsonResponse()
            {
                Result = results
            }, RpcContext));

            //}
            //catch (Exception ex)
            //{
            //    JsonResponse response;
            //    if (ex is TargetParameterCountException)
            //    {
            //        response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32602, "Invalid params", ex)) };
            //        return PostProcess(callback, Rpc, response, RpcContext);
            //    }

            //    // We really dont care about the TargetInvocationException, just pass on the inner exception
            //    if (ex is JsonRpcException)
            //    {
            //        response = new JsonResponse() { Error = ProcessException(Rpc, ex as JsonRpcException) };
            //        return PostProcess(callback, Rpc, response, RpcContext);
            //    }
            //    if (ex.InnerException != null && ex.InnerException is JsonRpcException)
            //    {
            //        response = new JsonResponse() { Error = ProcessException(Rpc, ex.InnerException as JsonRpcException) };
            //        return PostProcess(callback, Rpc, response, RpcContext);
            //    }
            //    else if (ex.InnerException != null)
            //    {
            //        response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex.InnerException)) };
            //        return PostProcess(callback, Rpc, response, RpcContext);
            //    }

            //    response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex)) };
            //    return PostProcess(callback, Rpc, response, RpcContext);
            //}
            //finally
            //{
            RemoveRpcContext();
            //}
        }
コード例 #8
0
        private static string ProcessInternal(string sessionId, string jsonRpc, object jsonRpcContext)
        {
            var handler = Handler.GetSessionHandler(sessionId);


            JsonRequest[] batch = null;
            try
            {
                if (isSingleRpc(jsonRpc))
                {
                    var foo = JsonConvert.DeserializeObject <JsonRequest>(jsonRpc);
                    batch = new[] { foo };
                }
                else
                {
                    batch = JsonConvert.DeserializeObject <JsonRequest[]>(jsonRpc);
                }
            }
            catch (Exception ex)
            {
                return(Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse
                {
                    Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(-32700, "Parse error", ex))
                }));
            }

            if (batch.Length == 0)
            {
                return(Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse
                {
                    Error = handler.ProcessParseException(jsonRpc,
                                                          new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty."))
                }));
            }

            var           singleBatch = batch.Length == 1;
            StringBuilder sbResult    = null;

            for (var i = 0; i < batch.Length; i++)
            {
                var jsonRequest  = batch[i];
                var jsonResponse = new JsonResponse();

                if (jsonRequest == null)
                {
                    jsonResponse.Error = handler.ProcessParseException(jsonRpc,
                                                                       new JsonRpcException(-32700, "Parse error",
                                                                                            "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."));
                }
                else if (jsonRequest.Method == null)
                {
                    jsonResponse.Error = handler.ProcessParseException(jsonRpc,
                                                                       new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                }
                else
                {
                    jsonResponse.Id = jsonRequest.Id;

                    var data = handler.Handle(jsonRequest, jsonRpcContext);

                    if (data == null)
                    {
                        continue;
                    }

                    jsonResponse.Error  = data.Error;
                    jsonResponse.Result = data.Result;
                }
                if (jsonResponse.Result == null && jsonResponse.Error == null)
                {
                    // Per json rpc 2.0 spec
                    // result : This member is REQUIRED on success.
                    // This member MUST NOT exist if there was an error invoking the method.
                    // Either the result member or error member MUST be included, but both members MUST NOT be included.
                    jsonResponse.Result = new Newtonsoft.Json.Linq.JValue((Object)null);
                }
                // special case optimization for single Item batch
                if (singleBatch && (jsonResponse.Id != null || jsonResponse.Error != null))
                {
                    StringWriter   sw     = new StringWriter();
                    JsonTextWriter writer = new JsonTextWriter(sw);
                    writer.WriteStartObject();
                    writer.WritePropertyName("jsonrpc"); writer.WriteValue("2.0");

                    if (jsonResponse.Error != null)
                    {
                        writer.WritePropertyName("error"); writer.WriteRawValue(JsonConvert.SerializeObject(jsonResponse.Error));
                    }
                    else
                    {
                        writer.WritePropertyName("result"); writer.WriteRawValue(JsonConvert.SerializeObject(jsonResponse.Result));
                    }
                    writer.WritePropertyName("id"); writer.WriteValue(jsonResponse.Id);
                    writer.WriteEndObject();
                    return(sw.ToString());

                    //return JsonConvert.SerializeObject(jsonResponse);
                }
                else if (jsonResponse.Id == null && jsonResponse.Error == null)
                {
                    // do nothing
                    sbResult = new StringBuilder(0);
                }
                else
                {
                    // write out the response
                    if (i == 0)
                    {
                        sbResult = new StringBuilder("[");
                    }

                    sbResult.Append(JsonConvert.SerializeObject(jsonResponse));
                    if (i < batch.Length - 1)
                    {
                        sbResult.Append(',');
                    }
                    else if (i == batch.Length - 1)
                    {
                        sbResult.Append(']');
                    }
                }
            }
            return(sbResult.ToString());
        }
コード例 #9
0
        /// <summary>
        /// Invokes a method to handle a JsonRpc request.
        /// </summary>
        /// <param name="Rpc">JsonRpc Request to be processed</param>
        /// <param name="RpcContext">Optional context that will be available from within the jsonRpcMethod.</param>
        /// <returns></returns>
        public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
        {
            AddRpcContext(RpcContext);

            var preProcessingException = PreProcess(Rpc, RpcContext);

            if (preProcessingException != null)
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = preProcessingException,
                    Id    = Rpc.Id
                };
                //callback is called - if it is empty then nothing will be done
                //return response always- if callback is empty or not
                return(PostProcess(Rpc, response, RpcContext));
            }

            SMDService metadata = null;
            Delegate   handle   = null;

            if (this.MetaData.Services.TryGetValue(Rpc.Method, out metadata))
            {
                handle = metadata.dele;
            }
            else if (metadata == null)
            {
                JsonResponse response = new JsonResponse()
                {
                    Result = null,
                    Error  = new JsonRpcException(-32601, "Method not found", "The method does not exist / is not available."),
                    Id     = Rpc.Id
                };
                return(PostProcess(Rpc, response, RpcContext));
            }

            object[] parameters          = null;
            bool     expectsRefException = false;
            var      metaDataParamCount  = metadata.parameters.Count(x => x != null);


            var loopCt   = 0;
            var getCount = Rpc.Params as ICollection;

            if (getCount != null)
            {
                loopCt = getCount.Count;
            }

            var paramCount = loopCt;

            if (paramCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount - 1].ObjectType.Name.Equals(Name_of_JSONRPCEXCEPTION))
            {
                paramCount++;
                expectsRefException = true;
            }
            parameters = new object[paramCount];

            if (Rpc.Params is Newtonsoft.Json.Linq.JArray)
            {
                var jarr = ((Newtonsoft.Json.Linq.JArray)Rpc.Params);
                for (int i = 0; i < loopCt && i < metadata.parameters.Length; i++)
                {
                    parameters[i] = CleanUpParameter(jarr[i], metadata.parameters[i]);
                }
            }
            else if (Rpc.Params is Newtonsoft.Json.Linq.JObject)
            {
                var asDict = Rpc.Params as IDictionary <string, Newtonsoft.Json.Linq.JToken>;
                for (int i = 0; i < loopCt && i < metadata.parameters.Length; i++)
                {
                    if (asDict.ContainsKey(metadata.parameters[i].Name) == true)
                    {
                        parameters[i] = CleanUpParameter(asDict[metadata.parameters[i].Name], metadata.parameters[i]);
                        continue;
                    }
                    else
                    {
                        JsonResponse response = new JsonResponse()
                        {
                            Error = ProcessException(Rpc,
                                                     new JsonRpcException(-32602,
                                                                          "Invalid params",
                                                                          string.Format("Named parameter '{0}' was not present.",
                                                                                        metadata.parameters[i].Name)
                                                                          )),
                            Id = Rpc.Id
                        };
                        return(PostProcess(Rpc, response, RpcContext));
                    }
                }
            }

            // Optional Parameter support
            // check if we still miss parameters compared to metadata which may include optional parameters.
            // if the rpc-call didn't supply a value for an optional parameter, we should be assinging the default value of it.
            if (parameters.Length < metaDataParamCount && metadata.defaultValues.Length > 0)                   // rpc call didn't set values for all optional parameters, so we need to assign the default values for them.
            {
                var suppliedParamsCount = parameters.Length;                                                   // the index we should start storing default values of optional parameters.
                var missingParamsCount  = metaDataParamCount - parameters.Length;                              // the amount of optional parameters without a value set by rpc-call.
                Array.Resize(ref parameters, parameters.Length + missingParamsCount);                          // resize the array to include all optional parameters.

                for (int paramIndex = parameters.Length - 1, defaultIndex = metadata.defaultValues.Length - 1; // fill missing parameters from the back
                     paramIndex >= suppliedParamsCount && defaultIndex >= 0;                                   // to don't overwrite supplied ones.
                     paramIndex--, defaultIndex--)
                {
                    parameters[paramIndex] = metadata.defaultValues[defaultIndex].Value;
                }

                if (missingParamsCount > metadata.defaultValues.Length)
                {
                    JsonResponse response = new JsonResponse
                    {
                        Error = ProcessException(Rpc,
                                                 new JsonRpcException(-32602,
                                                                      "Invalid params",
                                                                      string.Format(
                                                                          "Number of default parameters {0} not sufficient to fill all missing parameters {1}",
                                                                          metadata.defaultValues.Length, missingParamsCount)
                                                                      )),
                        Id = Rpc.Id
                    };
                    return(PostProcess(Rpc, response, RpcContext));
                }
            }

            if (parameters.Length != metaDataParamCount)
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = ProcessException(Rpc,
                                             new JsonRpcException(-32602,
                                                                  "Invalid params",
                                                                  string.Format("Expecting {0} parameters, and received {1}",
                                                                                metadata.parameters.Length,
                                                                                parameters.Length)
                                                                  )),
                    Id = Rpc.Id
                };
                return(PostProcess(Rpc, response, RpcContext));
            }

            try
            {
                var results = handle.DynamicInvoke(parameters);

                var          last             = parameters.LastOrDefault();
                var          contextException = RpcGetAndRemoveRpcException();
                JsonResponse response         = null;
                if (contextException != null)
                {
                    response = new JsonResponse()
                    {
                        Error = ProcessException(Rpc, contextException), Id = Rpc.Id
                    };
                }
                else if (expectsRefException && last != null && last is JsonRpcException)
                {
                    response = new JsonResponse()
                    {
                        Error = ProcessException(Rpc, last as JsonRpcException), Id = Rpc.Id
                    };
                }
                else
                {
                    response = new JsonResponse()
                    {
                        Result = results
                    };
                }
                return(PostProcess(Rpc, response, RpcContext));
            }
            catch (Exception ex)
            {
                JsonResponse response;
                if (ex is TargetParameterCountException)
                {
                    response = new JsonResponse()
                    {
                        Error = ProcessException(Rpc, new JsonRpcException(-32602, "Invalid params", ex))
                    };
                    return(PostProcess(Rpc, response, RpcContext));
                }

                // We really dont care about the TargetInvocationException, just pass on the inner exception
                if (ex is JsonRpcException)
                {
                    response = new JsonResponse()
                    {
                        Error = ProcessException(Rpc, ex as JsonRpcException)
                    };
                    return(PostProcess(Rpc, response, RpcContext));
                }
                if (ex.InnerException != null && ex.InnerException is JsonRpcException)
                {
                    response = new JsonResponse()
                    {
                        Error = ProcessException(Rpc, ex.InnerException as JsonRpcException)
                    };
                    return(PostProcess(Rpc, response, RpcContext));
                }
                else if (ex.InnerException != null)
                {
                    response = new JsonResponse()
                    {
                        Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex.InnerException))
                    };
                    return(PostProcess(Rpc, response, RpcContext));
                }

                response = new JsonResponse()
                {
                    Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex))
                };
                return(PostProcess(Rpc, response, RpcContext));
            }
            finally
            {
                RemoveRpcContext();
            }
        }
コード例 #10
0
        internal static void ProcessJsonRpcState(string sessionId, JsonRpcStateAsync async, object jsonRpcContext = null)
        {
            var context = async.AsyncState;

            JsonRequest[] rpcBatch = null;
            JsonResponse[] responseBatch = null;

            JsonRequest rpc = null;
            var handler = Handler.GetSessionHandler(sessionId);
            var callback = string.Empty;

            var response = new JsonResponse();

            response.Result = null;
            response.Error = null;

                string json = async.JsonRpc; 
                                
                if (isSingleRpc(json))
                {
                    try
                    {
                        if (json.Length > 0)
                        {
                            rpc = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonRequest>(json);
                            if (rpc == null)
                            {
                                response.Result = null;
                                response.Id = null;
                                response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."));
                            }
                            else
                            {
                                response.Id = rpc.Id;
                                if (rpc.Method == null)
                                {
                                    response.Result = null;
                                    response.Id = rpc.Id;
                                    response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                                }
                            }
                        }
                        else
                        {
                            response.Result = null;
                            response.Id = null;
                            response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "The JSON sent is not a valid Request object."));
                        }
                    }
                    catch (Exception ex)
                    {
                        response.Result = null;
                        if (rpc != null) response.Id = rpc.Id;
                        response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex));
                        var result = Newtonsoft.Json.JsonConvert.SerializeObject(response);
                        async.Result = result;                        
                        async.SetCompleted();
                        return;
                    }
                    
                    if (response.Error == null
                        && rpc != null
                        && rpc.Method != null)
                    {
                        var data = Handler.GetSessionHandler(sessionId).Handle(rpc, jsonRpcContext);
                        if (data != null)
                        {
                            response.Error = data.Error;
                            response.Result = data.Result;
                            var result = "";
                            if (response.Id != null)// dont return a result for notifications
                            {
                                result=Newtonsoft.Json.JsonConvert.SerializeObject(response);
                            }
                            async.Result = result;
                            async.SetCompleted();
                            return;
                        }
                    }

                    var err = Newtonsoft.Json.JsonConvert.SerializeObject(response);

                    async.Result = err;
                    async.SetCompleted();
                }
                else // this is a batch of requests
                {
                    try
                    {
                        rpcBatch = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonRequest[]>(json);
                        responseBatch = new JsonResponse[rpcBatch.Length];
                        
                        for (int i = 0; i < rpcBatch.Length; i++)
                        {
                            responseBatch[i] = new JsonResponse();
                            if (rpcBatch[i] == null)
                            {
                                responseBatch[i].Result = null;
                                responseBatch[i].Id = null;
                                responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."));
                            }
                            else
                            {
                                responseBatch[i].Id = rpcBatch[i].Id;
                                if (rpcBatch[i].Method == null)
                                {
                                    responseBatch[i].Result = null;
                                    responseBatch[i].Error =handler.ProcessParseException(json,  new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                                }
                            }
                        }                        
                    }
                    catch (Exception ex)
                    {
                        response.Result = null;
                        if (rpc != null) response.Id = rpc.Id;
                        response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex));
                        var result = Newtonsoft.Json.JsonConvert.SerializeObject(response);
                        async.Result = result;
                        async.SetCompleted();
                        return;
                    }

                    // we should have a batch of RPC at this point
                    var respBuilder = new StringBuilder();
                    for (int i = 0; i < rpcBatch.Length; i++)
                    {
                        if (i == 0)
                        {
                            respBuilder.Append("[");
                        }

                        if (rpcBatch[i] == null || rpcBatch[i].Method == null)
                        {
                            responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                        }
                        else if (responseBatch[i].Error == null)
                        {
                            var data = handler.Handle(rpcBatch[i], jsonRpcContext);
                            if (data != null)
                            {
                                responseBatch[i].Error = data.Error;
                                responseBatch[i].Result = data.Result;
                                                            
                            }
                        }
                        // dont return a response for notifications.
                        if (responseBatch[i].Id != null || responseBatch[i].Error != null)
                        {
                            var result = Newtonsoft.Json.JsonConvert.SerializeObject(responseBatch[i]);
                            respBuilder.Append(result);
                            if (i != rpcBatch.Length - 1)
                            {
                                respBuilder.Append(',');
                            }
                        }

                        if (i == rpcBatch.Length - 1)
                        {
                            respBuilder.Append("]");
                            var str = respBuilder.ToString();
                            async.Result = str;
                            async.SetCompleted(); // let IIS think we are completed now.
                            return;
                        }
                    }

                    // if we made it this far, then there were no items in the array
                    response.Id = null;
                    response.Result = null;
                    response.Error = handler.ProcessParseException(json, new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty."));

                    var err = Newtonsoft.Json.JsonConvert.SerializeObject(response);

                    async.Result = err;
                    async.SetCompleted();
                }     
        }
コード例 #11
0
        public static Task<string> Process(string sessionId, string jsonRpc, object context = null)
        {
            var task = Task<string>.Factory.StartNew((_) => 
            {
                // use invariant culture - we have to set it explicitly for every thread we create to 
                // prevent any floating-point problems (mostly because of number formats in non en-US cultures).
                Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
                
                var tup = (Tuple<string,string,object>)_;
                string _sessionId;
                string _jsonRpc;
                object _jsonRpcContext = null;
                _sessionId = tup.Item1;
                _jsonRpc = tup.Item2;
                _jsonRpcContext = tup.Item3;
                var handler = Handler.GetSessionHandler(_sessionId);


                JsonRequest[] rpcBatch = null;
                JsonResponse[] responseBatch = null;

                JsonRequest rpc = null;

                var callback = string.Empty;

                var response = new JsonResponse();

                response.Result = null;
                response.Error = null;

                string json = _jsonRpc;

                if (isSingleRpc(json))
                {
                    try
                    {
                        if (json.Length > 0)
                        {
                            rpc = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonRequest>(json);
                            if (rpc == null)
                            {
                                response.Result = null;
                                response.Id = null;
                                response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."));
                            }
                            else
                            {
                                response.Id = rpc.Id;
                                if (rpc.Method == null)
                                {
                                    response.Result = null;
                                    response.Id = rpc.Id;
                                    response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                                }
                            }
                        }
                        else
                        {
                            response.Result = null;
                            response.Id = null;
                            response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "The JSON sent is not a valid Request object."));
                        }
                    }
                    catch (Exception ex)
                    {
                        response.Result = null;
                        if (rpc != null) response.Id = rpc.Id;
                        response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex));
                        var result = Newtonsoft.Json.JsonConvert.SerializeObject(response);
                        return result;
                    }

                    if (response.Error == null
                        && rpc != null
                        && rpc.Method != null)
                    {
                        var data = handler.Handle(rpc, _jsonRpcContext);
                        if (data != null)
                        {
                            response.Error = data.Error;
                            response.Result = data.Result;
                            var result = "";
                            if (response.Id != null)// dont return a result for notifications
                            {
                                result = Newtonsoft.Json.JsonConvert.SerializeObject(response);
                            }
                            return result;
                        }
                    }

                    var err = Newtonsoft.Json.JsonConvert.SerializeObject(response);

                    return err;
                }
                else // this is a batch of requests
                {
                    try
                    {
                        rpcBatch = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonRequest[]>(json);
                        responseBatch = new JsonResponse[rpcBatch.Length];

                        for (int i = 0; i < rpcBatch.Length; i++)
                        {
                            responseBatch[i] = new JsonResponse();
                            if (rpcBatch[i] == null)
                            {
                                responseBatch[i].Result = null;
                                responseBatch[i].Id = null;
                                responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."));
                            }
                            else
                            {
                                responseBatch[i].Id = rpcBatch[i].Id;
                                if (rpcBatch[i].Method == null)
                                {
                                    responseBatch[i].Result = null;
                                    responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        response.Result = null;
                        if (rpc != null) response.Id = rpc.Id;
                        response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex));
                        var result = Newtonsoft.Json.JsonConvert.SerializeObject(response);
                        return result; 
                    }

                    // we should have a batch of RPC at this point
                    var respBuilder = new StringBuilder();
                    for (int i = 0; i < rpcBatch.Length; i++)
                    {
                        if (i == 0)
                        {
                            respBuilder.Append("[");
                        }

                        if (rpcBatch[i] == null || rpcBatch[i].Method == null)
                        {
                            responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
                        }
                        else if (responseBatch[i].Error == null)
                        {
                            var data = Handler.GetSessionHandler(_sessionId).Handle(rpcBatch[i], _jsonRpcContext);
                            if (data != null)
                            {
                                responseBatch[i].Error = data.Error;
                                responseBatch[i].Result = data.Result;

                            }
                        }
                        // dont return a response for notifications.
                        if (responseBatch[i].Id != null || responseBatch[i].Error != null)
                        {
                            var result = Newtonsoft.Json.JsonConvert.SerializeObject(responseBatch[i]);
                            respBuilder.Append(result);
                            if (i != rpcBatch.Length - 1)
                            {
                                respBuilder.Append(',');
                            }
                        }

                        if (i == rpcBatch.Length - 1)
                        {
                            respBuilder.Append("]");
                            var str = respBuilder.ToString();
                            return str;
                        }
                    }

                    // if we made it this far, then there were no items in the array
                    response.Id = null;
                    response.Result = null;
                    response.Error = handler.ProcessParseException(json, new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty."));

                    var err = Newtonsoft.Json.JsonConvert.SerializeObject(response);

                    return err;
                }
            }, new Tuple<string, string, object>(sessionId, jsonRpc, context));
            return task;
        }
コード例 #12
0
ファイル: Handler.cs プロジェクト: vebin/JSON-RPC.NET
        /// <summary>
        /// Invokes a method to handle a JsonRpc request.
        /// </summary>
        /// <param name="Rpc">JsonRpc Request to be processed</param>
        /// <param name="RpcContext">Optional context that will be available from within the jsonRpcMethod.</param>
        /// <returns></returns>
        public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null, Action<JsonResponse> callback = null)
        {
            //empty delegate declaration if callback is not provided
            if (null == callback)
            {
                callback = delegate(JsonResponse a) { };
            }

            AddRpcContext(RpcContext);

            var preProcessingException = PreProcess(Rpc, RpcContext);
            if (preProcessingException != null)
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = preProcessingException,
                    Id = Rpc.Id
                };
                //callback is called - if it is empty then nothing will be done
                callback.Invoke(response);
                //return response always- if callback is empty or not
                return response;
            }

            SMDService metadata = null;
            Delegate handle = null;
            var haveDelegate = this.Handlers.TryGetValue(Rpc.Method, out handle);
            var haveMetadata = this.MetaData.Services.TryGetValue(Rpc.Method, out metadata);

            if (haveDelegate == false || haveMetadata == false || metadata == null || handle == null)
            {
                JsonResponse response = new JsonResponse()
                {
                    Result = null,
                    Error = new JsonRpcException(-32601, "Method not found", "The method does not exist / is not available."),
                    Id = Rpc.Id
                };
                callback.Invoke(response);
                return response;
            }

            bool isJObject = Rpc.Params is Newtonsoft.Json.Linq.JObject;
            bool isJArray = Rpc.Params is Newtonsoft.Json.Linq.JArray;
            object[] parameters = null;
            bool expectsRefException = false;
            var metaDataParamCount = metadata.parameters.Count(x => x != null);

            var getCount = Rpc.Params as ICollection;
            var loopCt = 0;

            if (getCount != null)
            {
                loopCt = getCount.Count;
            }

            var paramCount = loopCt;
            if (paramCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount - 1].ObjectType.Name.Contains(typeof(JsonRpcException).Name))
            {
                paramCount++;
                expectsRefException = true;
            }
            parameters = new object[paramCount];

            if (isJArray)
            {
                var jarr = ((Newtonsoft.Json.Linq.JArray)Rpc.Params);
                //var loopCt = jarr.Count;
                //var pCount = loopCt;
                //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException))
                //    pCount++;
                //parameters = new object[pCount];
                for (int i = 0; i < loopCt; i++)
                {
                    parameters[i] = CleanUpParameter(jarr[i], metadata.parameters[i]);
                }
            }
            else if (isJObject)
            {
                var jo = Rpc.Params as Newtonsoft.Json.Linq.JObject;
                //var loopCt = jo.Count;
                //var pCount = loopCt;
                //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException))
                //    pCount++;
                //parameters = new object[pCount];
                var asDict = jo as IDictionary<string, Newtonsoft.Json.Linq.JToken>;
                for (int i = 0; i < loopCt; i++)
                {
                    if (asDict.ContainsKey(metadata.parameters[i].Name) == false)
                    {
                        JsonResponse response = new JsonResponse()
                        {
                            Error = ProcessException(Rpc,
                            new JsonRpcException(-32602,
                                "Invalid params",
                                string.Format("Named parameter '{0}' was not present.",
                                                metadata.parameters[i].Name)
                                )),
                            Id = Rpc.Id
                        };
                        callback.Invoke(response);
                        return response;
                    }
                    parameters[i] = CleanUpParameter(jo[metadata.parameters[i].Name], metadata.parameters[i]);
                }
            }

            // Optional Parameter support
            // check if we still miss parameters compared to metadata which may include optional parameters.
            // if the rpc-call didn't supply a value for an optional parameter, we should be assinging the default value of it.
            if (parameters.Length < metaDataParamCount && metadata.defaultValues.Length > 0) // rpc call didn't set values for all optional parameters, so we need to assign the default values for them.
            {
                var suppliedParamsCount = parameters.Length; // the index we should start storing default values of optional parameters.
                var missingParamsCount = metaDataParamCount - parameters.Length; // the amount of optional parameters without a value set by rpc-call.
                Array.Resize(ref parameters, parameters.Length + missingParamsCount); // resize the array to include all optional parameters.

                for (int paramIndex = parameters.Length - 1, defaultIndex = metadata.defaultValues.Length - 1;     // fill missing parameters from the back 
                    paramIndex >= suppliedParamsCount && defaultIndex >= 0;                                        // to don't overwrite supplied ones.
                    paramIndex--, defaultIndex--)
                {
                    parameters[paramIndex] = metadata.defaultValues[defaultIndex].Value;
                }

                if (missingParamsCount > metadata.defaultValues.Length)
                {
                    JsonResponse response = new JsonResponse
                    {
                        Error = ProcessException(Rpc,
                            new JsonRpcException(-32602,
                                "Invalid params",
                                string.Format(
                                    "Number of default parameters {0} not sufficient to fill all missing parameters {1}",
                                    metadata.defaultValues.Length, missingParamsCount)
                                )),
                        Id = Rpc.Id
                    };
                    callback.Invoke(response);
                    return response;
                }
            }

            if (parameters.Length != metaDataParamCount)
            {
                JsonResponse response = new JsonResponse()
                {
                    Error = ProcessException(Rpc,
                    new JsonRpcException(-32602,
                        "Invalid params",
                        string.Format("Expecting {0} parameters, and received {1}",
                                        metadata.parameters.Length,
                                        parameters.Length)
                        )),
                    Id = Rpc.Id
                };
                callback.Invoke(response);
                return response;
            }

            try
            {
                //callback is stored to thread's local storage in order to get it directly from concrete JsonRpcService method implementation
                //where callback is just returned from method
               Thread.SetData(Thread.GetNamedDataSlot(THREAD_CALLBACK_SLOT_NAME), callback);
               
                
                var results = handle.DynamicInvoke(parameters);
                
                var last = parameters.LastOrDefault();
                JsonRpcException contextException;
                if (Task.CurrentId.HasValue && RpcExceptions.TryRemove(Task.CurrentId.Value, out contextException))
                {
                    JsonResponse response = new JsonResponse() { Error = ProcessException(Rpc, contextException), Id = Rpc.Id };
                    callback.Invoke(response);
                    return response;
                }
                if (expectsRefException && last != null && last is JsonRpcException)
                {
                    JsonResponse response = new JsonResponse() { Error = ProcessException(Rpc, last as JsonRpcException), Id = Rpc.Id };
                    callback.Invoke(response);
                    return response;
                }
                //return response, if callback is set (method is asynchronous) - result could be empty string and future result operations
                //will be processed in the callback
                return new JsonResponse() { Result = results };
            }
            catch (Exception ex)
            {
                JsonResponse response;
                if (ex is TargetParameterCountException)
                {
                    response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32602, "Invalid params", ex)) };
                    callback.Invoke(response);
                    return response;
                }

                // We really dont care about the TargetInvocationException, just pass on the inner exception
                if (ex is JsonRpcException)
                {
                    response = new JsonResponse() { Error = ProcessException(Rpc, ex as JsonRpcException) };
                    callback.Invoke(response);
                    return response;
                }
                if (ex.InnerException != null && ex.InnerException is JsonRpcException)
                {
                    response = new JsonResponse() { Error = ProcessException(Rpc, ex.InnerException as JsonRpcException) };
                    callback.Invoke(response);
                    return response;
                }
                else if (ex.InnerException != null)
                {
                    response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex.InnerException)) };
                    callback.Invoke(response);
                    return response;
                }

                response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex)) };
                callback.Invoke(response);
                return response;
            }
            finally
            {
                RemoveRpcContext();
            }
        }
コード例 #13
0
ファイル: Handler.cs プロジェクト: yaozd/JSON-RPC.NET
        private JsonResponse PostProcess(Action<JsonResponse> callback, JsonRequest request, JsonResponse response, object context)
        {
            if (externalPostProcessingHandler != null)
            {
                try
                {
                    JsonRpcException exception = externalPostProcessingHandler(request, response, context);
                    if (exception != null)
                    {
                        response = new JsonResponse() { Error = exception };
                    }
                }
                catch (Exception ex)
                {
                    response = new JsonResponse() { Error = ProcessException(request, new JsonRpcException(-32603, "Internal Error", ex)) };
                }
            }

            if (callback != null)
                callback.Invoke(response);

            return response;
        }
コード例 #14
0
ファイル: client.cs プロジェクト: zhaxg/JSON-RPC.NET
        public IObservable <JsonResponse <T> > Invoke <T>(JsonRequest jsonRpc, IScheduler scheduler)
        {
            var res = Observable.Create <JsonResponse <T> >((obs) =>
                                                            scheduler.Schedule(() => {
                WebRequest req = null;
                try
                {
                    int myId;
                    lock (idLock)
                    {
                        myId = ++id;
                    }
                    jsonRpc.Id      = myId.ToString();
                    req             = HttpWebRequest.Create(new Uri(ServiceEndpoint, "?callid=" + myId.ToString()));
                    req.Method      = "Post";
                    req.ContentType = "application/json-rpc";
                }
                catch (Exception ex)
                {
                    obs.OnError(ex);
                }

                var ar = req.BeginGetRequestStream(new AsyncCallback((iar) =>
                {
                    HttpWebRequest request = null;

                    try
                    {
                        request    = (HttpWebRequest)iar.AsyncState;
                        var stream = new StreamWriter(req.EndGetRequestStream(iar));
                        var json   = Newtonsoft.Json.JsonConvert.SerializeObject(jsonRpc);
                        stream.Write(json);

                        stream.Close();
                    }
                    catch (Exception ex)
                    {
                        obs.OnError(ex);
                    }

                    var rar = req.BeginGetResponse(new AsyncCallback((riar) =>
                    {
                        JsonResponse <T> rjson = null;
                        string sstream         = "";
                        try
                        {
                            var request1 = (HttpWebRequest)riar.AsyncState;
                            var resp     = (HttpWebResponse)request1.EndGetResponse(riar);

                            using (var rstream = new StreamReader(CopyAndClose(resp.GetResponseStream())))
                            {
                                sstream = rstream.ReadToEnd();
                            }

                            rjson = Newtonsoft.Json.JsonConvert.DeserializeObject <JsonResponse <T> >(sstream);
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine(ex.Message);
                            Debugger.Break();
                        }

                        if (rjson == null)
                        {
                            if (!string.IsNullOrEmpty(sstream))
                            {
                                JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(sstream) as JObject;
                                obs.OnError(new Exception(jo["Error"].ToString()));
                            }
                            else
                            {
                                obs.OnError(new Exception("Empty response"));
                            }
                        }

                        obs.OnNext(rjson);
                        obs.OnCompleted();
                    }), request);
                }), req);
            }));

            return(res);
        }