diff --git a/.gitignore b/.gitignore
index 11908c9..d5b7685 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,6 +43,7 @@ ipch/
*.ncb
*.opensdf
*.sdf
+.vs
# Visual Studio profiler
*.psess
diff --git a/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj b/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj
index f026b13..a134fea 100644
--- a/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj
+++ b/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj
@@ -9,7 +9,7 @@
Properties
AustinHarris.JsonRpc.AspNet
AustinHarris.JsonRpc.AspNet
- v4.0
+ v4.5
512
SAK
SAK
@@ -17,6 +17,7 @@
SAK
..\
true
+
true
@@ -26,6 +27,7 @@
DEBUG;TRACE
prompt
4
+ false
pdbonly
@@ -34,11 +36,11 @@
TRACE
prompt
4
+ false
-
- ..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll
- True
+
+ ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
diff --git a/AustinHarris.JsonRpc.AspNet/packages.config b/AustinHarris.JsonRpc.AspNet/packages.config
index 7c276ed..c8b3ae6 100644
--- a/AustinHarris.JsonRpc.AspNet/packages.config
+++ b/AustinHarris.JsonRpc.AspNet/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/AustinHarris.JsonRpcTestN/AustinHarris.JsonRpcTestN.csproj b/AustinHarris.JsonRpcTestN/AustinHarris.JsonRpcTestN.csproj
index fe8c6d8..ce26feb 100644
--- a/AustinHarris.JsonRpcTestN/AustinHarris.JsonRpcTestN.csproj
+++ b/AustinHarris.JsonRpcTestN/AustinHarris.JsonRpcTestN.csproj
@@ -30,9 +30,8 @@
false
-
- ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
- True
+
+ ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
..\packages\NUnit.2.6.4\lib\nunit.framework.dll
diff --git a/AustinHarris.JsonRpcTestN/Test.cs b/AustinHarris.JsonRpcTestN/Test.cs
index 3fd2e7f..426f4b1 100644
--- a/AustinHarris.JsonRpcTestN/Test.cs
+++ b/AustinHarris.JsonRpcTestN/Test.cs
@@ -68,7 +68,7 @@ public void TestCanCreateAndRemoveSession()
Tuple.Create ("sooper", typeof(string)),
Tuple.Create ("returns", typeof(string))
}.ToDictionary(x => x.Item1, x => x.Item2);
- h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(),new Func(x => "workie ... " + x));
+ h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(), "",new Func(x => "workie ... " + x));
string request = @"{method:'workie',params:{'sooper':'good'},id:1}";
string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"workie ... good\",\"id\":1}";
@@ -1571,7 +1571,7 @@ public void TestPreProcessOnSession()
Tuple.Create ("sooper", typeof(string)),
Tuple.Create ("returns", typeof(string))
}.ToDictionary(x => x.Item1, x => x.Item2);
- h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(),new Func(x => "workie ... " + x));
+ h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(), "", new Func(x => "workie ... " + x));
string request = @"{method:'workie',params:{'sooper':'good'},id:1}";
string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"workie ... good\",\"id\":1}";
@@ -1811,7 +1811,7 @@ public void TestPostProcessOnSession()
Tuple.Create ("sooper", typeof(string)),
Tuple.Create ("returns", typeof(string))
}.ToDictionary(x => x.Item1, x => x.Item2);
- h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(), new Func(x => "workie ... " + x));
+ h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(), "", new Func(x => "workie ... " + x));
string request = @"{method:'workie',params:{'sooper':'good'},id:1}";
string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"workie ... good\",\"id\":1}";
diff --git a/AustinHarris.JsonRpcTestN/packages.config b/AustinHarris.JsonRpcTestN/packages.config
index 3632280..f19116d 100644
--- a/AustinHarris.JsonRpcTestN/packages.config
+++ b/AustinHarris.JsonRpcTestN/packages.config
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/AustinHarris.JsonRpcTestN/service.cs b/AustinHarris.JsonRpcTestN/service.cs
index 623a0e8..7a823ae 100644
--- a/AustinHarris.JsonRpcTestN/service.cs
+++ b/AustinHarris.JsonRpcTestN/service.cs
@@ -343,13 +343,6 @@ public string TestPreProcessorThrowsException(string inputValue)
throw new Exception("TestException");
}
- [JsonRpcMethod]
- public string TestPreProcessorSetsException(string inputValue)
- {
- JsonRpcContext.SetException(new JsonRpcException(-27000, "This exception was thrown using: JsonRpcContext.SetException()", null));
- return null;
- }
-
[JsonRpcMethod]
public string TestPostProcessor(string inputValue)
{
@@ -368,13 +361,6 @@ public string TestPostProcessorThrowsException(string inputValue)
throw new Exception("TestException");
}
- [JsonRpcMethod]
- public string TestPostProcessorSetsException(string inputValue)
- {
- JsonRpcContext.SetException(new JsonRpcException(-27001, "This exception was thrown using: JsonRpcContext.SetException()", null));
- return null;
- }
-
[JsonRpcMethod]
public TreeNode TestNestedReturnType()
{
diff --git a/Json-Rpc/Attributes.cs b/Json-Rpc/Attributes.cs
index 1592511..1131d5e 100644
--- a/Json-Rpc/Attributes.cs
+++ b/Json-Rpc/Attributes.cs
@@ -47,4 +47,13 @@ public string JsonParamName
get { return jsonParamName; }
}
}
+
+ ///
+ /// Used to assign context parameter.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
+ public sealed class JsonRpcContextAttribute : Attribute
+ {
+
+ }
}
diff --git a/Json-Rpc/AustinHarris.JsonRpc.csproj b/Json-Rpc/AustinHarris.JsonRpc.csproj
index 9d97aeb..d103721 100644
--- a/Json-Rpc/AustinHarris.JsonRpc.csproj
+++ b/Json-Rpc/AustinHarris.JsonRpc.csproj
@@ -17,7 +17,7 @@
SAK
..\..\CoiniumServ\build\
true
- v4.0
+ v4.5
AnyCPU
@@ -47,6 +47,7 @@
TRACE;DEBUG
4
false
+ false
AnyCPU
@@ -54,6 +55,7 @@
4
true
false
+ false
@@ -73,9 +75,8 @@
-
- ..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll
- True
+
+ ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
diff --git a/Json-Rpc/Handler.cs b/Json-Rpc/Handler.cs
index 474ff91..54356d6 100644
--- a/Json-Rpc/Handler.cs
+++ b/Json-Rpc/Handler.cs
@@ -109,34 +109,6 @@ public void Destroy()
///
public string SessionId { get; private set; }
- ///
- /// Provides access to a context specific to each JsonRpc method invocation.
- /// Warning: Must be called from within the execution context of the jsonRpc Method to return the context
- ///
- ///
- public static object RpcContext()
- {
- return __currentRpcContext;
- }
-
- [ThreadStatic]
- static JsonRpcException __currentRpcException;
- ///
- /// Allows you to set the exception used in in the JsonRpc response.
- /// Warning: Must be called from the same thread as the jsonRpc method.
- ///
- ///
- public static void RpcSetException(JsonRpcException exception)
- {
- __currentRpcException = exception;
- }
- public static JsonRpcException RpcGetAndRemoveRpcException()
- {
- var ex = __currentRpcException;
- __currentRpcException = null ;
- return ex;
- }
-
private AustinHarris.JsonRpc.PreProcessHandler externalPreProcessingHandler;
private AustinHarris.JsonRpc.PostProcessHandler externalPostProcessingHandler;
private Func externalErrorHandler;
@@ -168,9 +140,9 @@ public static void RegisterInstance(string sessionID, object instance)
/// The parameter names and types that will be positionally bound to the function
/// Optional default values for parameters
/// A reference to the Function
- public void RegisterFuction(string methodName, Dictionary parameterNameTypeMapping, Dictionary parameterNameDefaultValueMapping, Delegate implementation)
+ public void RegisterFuction(string methodName, Dictionary parameterNameTypeMapping, Dictionary parameterNameDefaultValueMapping, string contextParameter, Delegate implementation)
{
- MetaData.AddService(methodName, parameterNameTypeMapping, parameterNameDefaultValueMapping, implementation);
+ MetaData.AddService(methodName, parameterNameTypeMapping, parameterNameDefaultValueMapping, contextParameter, implementation);
}
public void UnRegisterFunction(string methodName)
@@ -194,10 +166,8 @@ public void SetPostProcessHandler(AustinHarris.JsonRpc.PostProcessHandler handle
/// JsonRpc Request to be processed
/// Optional context that will be available from within the jsonRpcMethod.
///
- public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
+ public async Task Handle(JsonRequest Rpc, Object RpcContext = null)
{
- AddRpcContext(RpcContext);
-
var preProcessingException = PreProcess(Rpc, RpcContext);
if (preProcessingException != null)
{
@@ -250,9 +220,19 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
if (Rpc.Params is Newtonsoft.Json.Linq.JArray)
{
var jarr = ((Newtonsoft.Json.Linq.JArray)Rpc.Params);
- for (int i = 0; i < loopCt; i++)
+ for (int i = 0, j = 0; i < loopCt; i++, j++)
{
- parameters[i] = CleanUpParameter(jarr[i], metadata.parameters[i]);
+ if (metadata.parameters[i].Name == metadata.contextParameter)
+ {
+ Array.Resize(ref parameters, parameters.Length + 1);
+ loopCt++;
+ parameters[i] = RpcContext;
+ j--;
+ }
+ else
+ {
+ parameters[i] = CleanUpParameter(jarr[j], metadata.parameters[i]);
+ }
}
}
else if (Rpc.Params is Newtonsoft.Json.Linq.JObject)
@@ -260,7 +240,13 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
var asDict = Rpc.Params as IDictionary;
for (int i = 0; i < loopCt && i < metadata.parameters.Length; i++)
{
- if (asDict.ContainsKey(metadata.parameters[i].Name) == true)
+ if (metadata.parameters[i].Name == metadata.contextParameter)
+ {
+ Array.Resize(ref parameters, parameters.Length + 1);
+ loopCt++;
+ parameters[i] = RpcContext;
+ }
+ else if (asDict.ContainsKey(metadata.parameters[i].Name) == true)
{
parameters[i] = CleanUpParameter(asDict[metadata.parameters[i].Name], metadata.parameters[i]);
continue;
@@ -282,23 +268,18 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
}
}
- // Optional Parameter support
- // check if we still miss parameters compared to metadata which may include optional parameters.
+ // Optional Parameter & Context Parameter support
+ // check if we still miss parameters compared to metadata which may include optional parameters or context parameter.
// 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.
+ if (parameters.Length < metaDataParamCount &&
+ (metadata.defaultValues.Length > 0 || !String.IsNullOrEmpty(metadata.contextParameter))) // 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.
+ var contextParamsCount = String.IsNullOrEmpty(metadata.contextParameter) ? 0 : 1;
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)
+ if (missingParamsCount > metadata.defaultValues.Length + contextParamsCount)
{
JsonResponse response = new JsonResponse
{
@@ -313,6 +294,22 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
};
return PostProcess(Rpc, response, RpcContext);
}
+
+ for (int paramIndex = parameters.Length - 1, defaultIndex = metadata.defaultValues.Length - 1; // fill missing parameters from the back
+ paramIndex >= suppliedParamsCount && (defaultIndex >= 0 || contextParamsCount > 0); // to don't overwrite supplied ones.
+ paramIndex--, defaultIndex--)
+ {
+ if (metadata.parameters[paramIndex].Name == metadata.contextParameter)
+ {
+ parameters[paramIndex] = RpcContext;
+ contextParamsCount--;
+ }
+ else
+ {
+ parameters[paramIndex] = metadata.defaultValues[defaultIndex].Value;
+ }
+ }
+
}
if (parameters.Length != metaDataParamCount)
@@ -333,16 +330,25 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
try
{
- var results = handle.DynamicInvoke(parameters);
-
- var last = parameters.LastOrDefault();
- var contextException = RpcGetAndRemoveRpcException();
- JsonResponse response = null;
- if (contextException != null)
+ object results = handle.DynamicInvoke(parameters);
+ if (results is Task)
{
- response = new JsonResponse() { Error = ProcessException(Rpc, contextException), Id = Rpc.Id };
+ var task = (Task)results;
+ await task;
+ PropertyInfo pInfo = task.GetType().GetRuntimeProperty("Result");
+ if (pInfo != null && !pInfo.PropertyType.Name.Equals("VoidTaskResult"))
+ {
+ results = pInfo.GetValue(task);
+ }
+ else
+ {
+ results = null;
+ }
}
- else if (expectsRefException && last != null && last is JsonRpcException)
+
+ var last = parameters.LastOrDefault();
+ JsonResponse response = null;
+ if (expectsRefException && last != null && last is JsonRpcException)
{
response = new JsonResponse() { Error = ProcessException(Rpc, last as JsonRpcException), Id = Rpc.Id };
}
@@ -383,22 +389,10 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null)
}
finally
{
- RemoveRpcContext();
}
}
#endregion
- [ThreadStatic]
- static object __currentRpcContext;
- private void AddRpcContext(object RpcContext)
- {
- __currentRpcContext = RpcContext;
- }
- private void RemoveRpcContext()
- {
- __currentRpcContext = null;
- }
-
private JsonRpcException ProcessException(JsonRequest req, JsonRpcException ex)
{
if (externalErrorHandler != null)
diff --git a/Json-Rpc/JsonRpcContext.cs b/Json-Rpc/JsonRpcContext.cs
index e9a5ee6..4e0f7b0 100644
--- a/Json-Rpc/JsonRpcContext.cs
+++ b/Json-Rpc/JsonRpcContext.cs
@@ -20,25 +20,5 @@ private JsonRpcContext(object value)
/// The data associated with this context.
///
public object Value { get; private set; }
-
- ///
- /// Allows you to set the exception used in in the JsonRpc response.
- /// Warning: Must be called from within the execution context of the jsonRpc method to function.
- ///
- ///
- public static void SetException(JsonRpcException exception)
- {
- Handler.RpcSetException(exception);
- }
-
-
- ///
- /// Must be called from within the execution context of the jsonRpc Method to return the context
- ///
- ///
- public static JsonRpcContext Current()
- {
- return new JsonRpcContext(Handler.RpcContext());
- }
}
}
diff --git a/Json-Rpc/JsonRpcProcessor.cs b/Json-Rpc/JsonRpcProcessor.cs
index fd2126f..0bcb668 100644
--- a/Json-Rpc/JsonRpcProcessor.cs
+++ b/Json-Rpc/JsonRpcProcessor.cs
@@ -27,36 +27,44 @@ public static void Process(string sessionId, JsonRpcStateAsync async, object con
async.SetCompleted();
});
}
- public static Task Process(string jsonRpc, object context = null)
+ public static async Task Process(string jsonRpc, object context = null)
{
- return Process(Handler.DefaultSessionId(), jsonRpc, context);
+ return await Process(Handler.DefaultSessionId(), jsonRpc, context);
}
- public static Task Process(string sessionId, string jsonRpc, object context = null)
- {
- return Task.Factory.StartNew((_) =>
- {
- var tuple = (Tuple)_;
- return ProcessInternal(tuple.Item1, tuple.Item2, tuple.Item3);
- }, new Tuple(sessionId, jsonRpc, context));
+ public static async Task Process(string sessionId, string jsonRpc, object context = null)
+ {
+ return await ProcessInternal(sessionId, jsonRpc, context);
}
- private static string ProcessInternal(string sessionId, string jsonRpc, object jsonRpcContext)
+ public static async Task Process(string jsonRpc, JsonRequest jsonRequest, object context = null)
{
- var handler = Handler.GetSessionHandler(sessionId);
+ return await Process(Handler.DefaultSessionId(), jsonRpc, jsonRequest, context);
+ }
+
+ public static async Task Process(string sessionId, string jsonRpc, JsonRequest jsonRequest, object context = null)
+ {
+ return await ProcessInternal(sessionId, jsonRpc, jsonRequest, context);
+ }
+ public static async Task Process(string jsonRpc, JsonRequest[] jsonRequests, object context = null)
+ {
+ return await Process(Handler.DefaultSessionId(), jsonRpc, jsonRequests, context);
+ }
+
+ public static async Task Process(string sessionId, string jsonRpc, JsonRequest[] jsonRequests, object context = null)
+ {
+ return await ProcessInternal(sessionId, jsonRpc, jsonRequests, context);
+ }
+
+ private static async Task ProcessInternal(string sessionId, string jsonRpc, object jsonRpcContext)
+ {
+ var handler = Handler.GetSessionHandler(sessionId);
JsonRequest[] batch = null;
+ bool singleBatch;
try
{
- if (isSingleRpc(jsonRpc))
- {
- var foo = JsonConvert.DeserializeObject(jsonRpc);
- batch = new[] { foo };
- }
- else
- {
- batch = JsonConvert.DeserializeObject(jsonRpc);
- }
+ batch = DeserializeRequest(jsonRpc, out singleBatch);
}
catch (Exception ex)
{
@@ -66,110 +74,171 @@ private static string ProcessInternal(string sessionId, string jsonRpc, object j
});
}
- if (batch.Length == 0)
+ JsonResponse[] jsonResponses = await ProcessInternal(sessionId, jsonRpc, batch, jsonRpcContext);
+ return SerializeResponse(jsonResponses, singleBatch);
+ }
+
+ private static async Task ProcessInternal(string sessionId, string jsonRpc, JsonRequest[] jsonRequests, object jsonRpcContext)
+ {
+ var handler = Handler.GetSessionHandler(sessionId);
+
+ if (jsonRequests.Length == 0)
{
- return Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse
+ return new JsonResponse[]
{
- Error = handler.ProcessParseException(jsonRpc,
- new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty."))
- });
+ new JsonResponse
+ {
+ Error = handler.ProcessParseException(jsonRpc,
+ new JsonRpcException(-32600, "Invalid Request", "Batch of calls was empty."))
+ }
+ };
}
- var singleBatch = batch.Length == 1;
- StringBuilder sbResult = null;
- for (var i = 0; i < batch.Length; i++)
+ List jsonResponses = null;
+ for (var i = 0; i < jsonRequests.Length; i++)
{
- var jsonRequest = batch[i];
- var jsonResponse = new JsonResponse();
+ var jsonRequest = jsonRequests[i];
+ var jsonResponse = await ProcessInternal(sessionId, jsonRpc, jsonRequest, jsonRpcContext);
- if (jsonRequest == null)
+ // single rpc optimization
+ if (jsonRequests.Length == 1 && (jsonResponse.Id != null || jsonResponse.Error != 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."));
+ return new JsonResponse[] { jsonResponse };
}
- else if (jsonRequest.Method == null)
+
+ if (jsonResponses == null)
{
- jsonResponse.Error = handler.ProcessParseException(jsonRpc,
- new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'"));
+ jsonResponses = new List();
}
- else
- {
- jsonResponse.Id = jsonRequest.Id;
+ jsonResponses.Add(jsonResponse);
+ }
+ return jsonResponses.ToArray();
+ }
- var data = handler.Handle(jsonRequest, jsonRpcContext);
+ private static async Task ProcessInternal(string sessionId, string jsonRpc, JsonRequest jsonRequest, object jsonRpcContext)
+ {
+ var handler = Handler.GetSessionHandler(sessionId);
- if (data == null) continue;
+ var jsonResponse = new JsonResponse();
- jsonResponse.Error = data.Error;
- jsonResponse.Result = data.Result;
+ 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(-32601, "Invalid Request", "Missing property 'method'"));
+ }
+ else
+ {
+ jsonResponse.Id = jsonRequest.Id;
- }
- 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");
+ var data = await handler.Handle(jsonRequest, jsonRpcContext);
- 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();
+ if (data == null) return null;
- //return JsonConvert.SerializeObject(jsonResponse);
- }
- else if (jsonResponse.Id == null && jsonResponse.Error == null)
+ jsonResponse.Error = data.Error;
+ jsonResponse.Result = data.Result;
+ }
+ return jsonResponse;
+ }
+
+ private static bool IsSingleRpc(string json)
+ {
+ for (int i = 0; i < json.Length; i++)
+ {
+ if (json[i] == '{') return true;
+ else if (json[i] == '[') return false;
+ }
+ return true;
+ }
+
+ public static JsonRequest[] DeserializeRequest(string jsonRpc, out bool isSingleRpc)
+ {
+ JsonRequest[] batch = null;
+ try
+ {
+ isSingleRpc = IsSingleRpc(jsonRpc);
+ if (isSingleRpc)
{
- // do nothing
- sbResult = new StringBuilder(0);
+ var foo = JsonConvert.DeserializeObject(jsonRpc);
+ batch = new[] { foo };
}
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(']');
- }
+ batch = JsonConvert.DeserializeObject(jsonRpc);
}
}
- return sbResult.ToString();
+ catch (Exception ex)
+ {
+ throw new JsonRpcException(-32700, "Parse error", ex);
+ }
+ return batch;
}
- private static bool isSingleRpc(string json)
+ public static string SerializeResponse(JsonResponse jsonResponse)
{
- for (int i = 0; i < json.Length; i++)
+ if (jsonResponse.Id == null && jsonResponse.Error == null)
{
- if (json[i] == '{') return true;
- else if (json[i] == '[') return false;
+ // notification returns empty string
+ return "";
}
- return true;
+
+ 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);
+ }
+
+ 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();
+ }
+
+ public static string SerializeResponse(IEnumerable jsonResponses, bool isSingleRpc)
+ {
+ if (isSingleRpc)
+ {
+ return SerializeResponse(jsonResponses.First());
+ }
+
+ StringBuilder sbResult = new StringBuilder(0);
+ foreach (JsonResponse jsonResponse in jsonResponses)
+ {
+ string str = SerializeResponse(jsonResponse);
+ if (str.Length == 0)
+ {
+ // this is notification
+ continue;
+ }
+
+ sbResult.Append(sbResult.Length == 0 ? "[" : ",");
+ sbResult.Append(str);
+ }
+ if (sbResult.Length > 0)
+ {
+ sbResult.Append("]");
+ }
+ return sbResult.ToString();
}
}
}
diff --git a/Json-Rpc/SMDService.cs b/Json-Rpc/SMDService.cs
index fe84bb5..488a827 100644
--- a/Json-Rpc/SMDService.cs
+++ b/Json-Rpc/SMDService.cs
@@ -34,9 +34,9 @@ public SMD ()
TypeHashes = new List();
}
- internal void AddService(string method, Dictionary parameters, Dictionary defaultValues, Delegate dele)
+ internal void AddService(string method, Dictionary parameters, Dictionary defaultValues, string contextParameter, Delegate dele)
{
- var newService = new SMDService(transport,"JSON-RPC-2.0",parameters, defaultValues, dele);
+ var newService = new SMDService(transport,"JSON-RPC-2.0",parameters, defaultValues, contextParameter, dele);
Services.Add(method,newService);
}
@@ -72,7 +72,7 @@ public class SMDService
/// URL, PATH, JSON, JSON-RPC-1.0, JSON-RPC-1.1, JSON-RPC-2.0
///
///
- public SMDService(string transport, string envelope, Dictionary parameters, Dictionary defaultValues, Delegate dele)
+ public SMDService(string transport, string envelope, Dictionary parameters, Dictionary defaultValues, string contextParameter, Delegate dele)
{
// TODO: Complete member initialization
this.dele = dele;
@@ -98,6 +98,8 @@ public SMDService(string transport, string envelope, Dictionary pa
// this is getting the return type from the end of the param list
this.returns = new SMDResult(parameters.Values.LastOrDefault());
+
+ this.contextParameter = contextParameter;
}
public string transport { get; private set; }
public string envelope { get; private set; }
@@ -116,6 +118,11 @@ public SMDService(string transport, string envelope, Dictionary pa
/// Stores default values for optional parameters.
///
public ParameterDefaultValue[] defaultValues { get; private set; }
+
+ ///
+ /// Stores context parameter name.
+ ///
+ public string contextParameter;
}
public class SMDResult
@@ -208,7 +215,23 @@ internal static int GetTypeRecursive(Type t)
if (item.PropertyType != t)
{
var jt = GetTypeRecursive(item.PropertyType);
- jo.Add(item.Name, jt);
+ ParameterInfo[] parameterInfos = item.GetIndexParameters();
+ if (parameterInfos?.Length > 0)
+ {
+ string name = item.Name + "[";
+ for (int i = 0; i < parameterInfos.Length; i++)
+ {
+ name += parameterInfos[i].ParameterType.Name;
+ if (i != parameterInfos.Length - 1)
+ name += ",";
+ }
+ name += "]";
+ jo.Add(name, jt);
+ }
+ else
+ {
+ jo.Add(item.Name, jt);
+ }
}
else
{
diff --git a/Json-Rpc/ServiceBinder.cs b/Json-Rpc/ServiceBinder.cs
index 20423a6..144d833 100644
--- a/Json-Rpc/ServiceBinder.cs
+++ b/Json-Rpc/ServiceBinder.cs
@@ -26,6 +26,7 @@ public static void BindService(string sessionID, Object instance)
{
Dictionary paras = new Dictionary();
Dictionary defaultValues = new Dictionary(); // dictionary that holds default values for optional params.
+ string contextParameter = null;
var paramzs = meth.GetParameters();
@@ -52,6 +53,14 @@ public static void BindService(string sessionID, Object instance)
if (paramzs[i].IsOptional) // if the parameter is an optional, add the default value to our default values dictionary.
defaultValues.Add(paramName, paramzs[i].DefaultValue);
+
+ var contextAttrs = paramzs[i].GetCustomAttributes(typeof(JsonRpcContextAttribute), false);
+ if (contextAttrs.Length > 0)
+ {
+ if (contextParameter != null)
+ throw new Exception("There are multiple context parameters: " + contextParameter + ", " + paramName);
+ contextParameter = paramName;
+ }
}
var resType = meth.ReturnType;
@@ -63,7 +72,7 @@ public static void BindService(string sessionID, Object instance)
var methodName = handlerAttribute.JsonMethodName == string.Empty ? meth.Name : handlerAttribute.JsonMethodName;
var newDel = Delegate.CreateDelegate(System.Linq.Expressions.Expression.GetDelegateType(paras.Values.ToArray()), instance /*Need to add support for other methods outside of this instance*/, meth);
var handlerSession = Handler.GetSessionHandler(sessionID);
- handlerSession.MetaData.AddService(methodName, paras, defaultValues, newDel);
+ handlerSession.MetaData.AddService(methodName, paras, defaultValues, contextParameter, newDel);
}
}
}
diff --git a/Json-Rpc/packages.config b/Json-Rpc/packages.config
index 7c276ed..c8b3ae6 100644
--- a/Json-Rpc/packages.config
+++ b/Json-Rpc/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/TestServer_Console/TestServer_Console.csproj b/TestServer_Console/TestServer_Console.csproj
index be9574b..0446212 100644
--- a/TestServer_Console/TestServer_Console.csproj
+++ b/TestServer_Console/TestServer_Console.csproj
@@ -8,8 +8,9 @@
Properties
TestServer_Console
TestServer_Console
- v4.0
- Client
+ v4.5
+
+
512
SAK
SAK
@@ -27,6 +28,7 @@
DEBUG;TRACE
prompt
4
+ false
x86
@@ -36,12 +38,14 @@
TRACE
prompt
4
+ false
AnyCPU
bin\Debug\
4
false
+ false
AnyCPU
@@ -49,11 +53,11 @@
4
true
false
+ false
-
- ..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll
- True
+
+ ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
@@ -78,6 +82,7 @@
+
diff --git a/TestServer_Console/packages.config b/TestServer_Console/packages.config
index e307e1c..c8b3ae6 100644
--- a/TestServer_Console/packages.config
+++ b/TestServer_Console/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file