microsoft / vs-streamjsonrpc の Formatter を MessagePack にして使う
Microsoft が提供している jsonrpc ライブラリ vs-streamjsonrpc
は Json 以外にも MessagePack でシリアライズ・デシリアライズできるように作成されています。
以前の記事 microsoft/vs-streamjsonrpc のバージョンが 2 になっていたので使ってみた。 - bamch0h’s diary を MessagePackで通信できるようにしてみたコードが以下。
JsonRpc.Attach
を使う代わりに、JsonRpc(IJsonRpcMessageHandler)
を使うのがミソ。ハンドラは LengthHeaderMessageHandler
を使います。HeaderDelimitedMessageHandler
が内部的にはデフォルトで使われているようですが、 Formatter が IJsonRpcMessageTextFormatter
を実装していないとダメなようなので使えません。なので、 LengthHeaderMessageHandler
を使います。
また、メソッドの引数や戻り値にクラスを指定する場合は各クラスにMessagePackの属性をつけておく必要があります。自身で定義している場合は属性付けれますが、サードパーティーが提供してくれているクラスを指定する場合はどうするんでしょうね。ラップクラスを自身で定義する必要がありそうです。
using System; using System.IO; using System.IO.Pipes; using System.Threading.Tasks; using StreamJsonRpc; using MessagePack; namespace ConsoleApp5 { public class Target { public int Add(int a, int b) { return a + b; } public Parameter Test(Parameter p) { p.Param1 += "-aaa"; p.Param2.Param2 += "-bbb"; return p; } } [MessagePackObject] public class Parameter { [Key(0)] public string Param1 { get; set; } [Key(1)] public SubParameter Param2 { get; set; } } [MessagePackObject] public class SubParameter { [Key(0)] public string Param2 { get; set; } } public class Client { public async Task Start(string pipename) { var stream = new NamedPipeClientStream(".", pipename, PipeDirection.InOut, PipeOptions.Asynchronous); stream.Connect(); var handler = new LengthHeaderMessageHandler(stream, stream, new MessagePackFormatter()); using (var rpc = Utils.NewRpc(handler)) { var ret = await rpc.InvokeAsync<int>("Add", new object[] { 1, 2 }); Console.WriteLine(ret); var ret2 = await rpc.InvokeAsync<Parameter>("Test", new Parameter() { Param1 = "1", Param2 = new SubParameter() { Param2 = "2" } }); Console.WriteLine(ret2.Param1); Console.WriteLine(ret2.Param2.Param2); } } } public class Server { public void Start(string pipename) { var stream = new NamedPipeServerStream(pipename, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); stream.WaitForConnection(); var handler = new LengthHeaderMessageHandler(stream, stream, new MessagePackFormatter()); using (var rpc = Utils.NewRpc(handler, new Target())) { rpc.Completion.Wait(); } } } public class Utils { public static JsonRpc NewRpc(IJsonRpcMessageHandler handler, object target = null) { var rpc = new JsonRpc(handler, target); try { rpc.StartListening(); return rpc; } catch { rpc.Dispose(); throw; } } } class Program { static void Main(string[] args) { string pipename = "winiotestpipe"; var ts = Task.Run(() => new Client().Start(pipename)); var tc = Task.Run(() => new Server().Start(pipename)); Task.WhenAll(tc, ts).Wait(); Console.ReadLine(); } } }