JSON-RPC.NET
JSON-RPC.NET copied to clipboard
Usage of await operator in the JsonRpcMethod.
Hello. I was wondering if it is possible to use the await operator in [JsonRpcMethod]
methods?
Inside the [JsonRpcMethod]
I would like to call asynchronous methods and return Task<T>
from the function. But this approach throws an exception. All I could do was call synchronous versions of the functions and return Task.FromResult
from the function.
Some examples:
using AustinHarris.JsonRpc;
object[] services = new object[] { new ExampleService() };
for (string line = Console.ReadLine(); !string.IsNullOrEmpty(line); line = Console.ReadLine())
{
try
{
var response = await JsonRpcProcessor.Process(line);
Console.WriteLine(response);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public class ExampleService : JsonRpcService
{
[JsonRpcMethod]
private async Task<double> DoSomethingAsync(double l, double r) // {'method':'DoSomethingAsync','params':[1.0,2.0],'id':1}
{
return await Worker.SummAsync(l, r);
}
}
public class Worker
{
public static async Task<double> SummAsync(double a, double b)
{
await Task.Delay(1000);
return await Task.FromResult(a + b);
}
}
Exception:
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'Task' with type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Double,ExampleService+<DoSomethingAsync>d__0]'. Path 'StateMachine.<>t__builder'.
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)
at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.SerializeObject(Object value)
at AustinHarris.JsonRpc.JsonRpcProcessor.ProcessSync(String sessionId, String jsonRpc, Object jsonRpcContext, JsonSerializerSettings settings)
at AustinHarris.JsonRpc.JsonRpcProcessor.<>c.<Process>b__3_0(Object _)
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Program.<Main>$(String[] args) in D:\Work\other\JsonRpcNetAsync\JsonRpcNetAsync\Program.cs:line 9
Working example:
using AustinHarris.JsonRpc;
object[] services = new object[] { new ExampleService() };
for (string line = Console.ReadLine(); !string.IsNullOrEmpty(line); line = Console.ReadLine())
{
try
{
Task<string> task1 = JsonRpcProcessor.Process(line);
Task<string> task2 = JsonRpcProcessor.Process(line);
Task<string> task3 = JsonRpcProcessor.Process(line);
Task<string>[] tasks = [task1, task2, task3];
string[] result = await Task.WhenAll(tasks);
foreach (string res in result) Console.WriteLine(res);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public class ExampleService : JsonRpcService
{
[JsonRpcMethod]
private Task<double> DoSomethingAsync(double l, double r) // {'method':'DoSomethingAsync','params':[1.0,2.0],'id':1}
{
return Task.FromResult(Worker.SummSync(l, r));
}
}
public class Worker
{
public static double SummSync(double a, double b)
{
Thread.Sleep(10000);
return a + b;
}
}
If I understand correctly, calling JsonRpcProcessor.Process(line)
runs in a separate thread, so blocking synchronous methods do not block the calling thread. But in the future, I might want to call asynchronous methods, and I was wondering if it is possible to do so using your framework? Thanks a lot for your answer!