microsoft/vs-streamjsonrpc のバージョンが 2 になっていたので使ってみた。

ほんとにさわりだけ使ってみただけ、使用感はさほど変わってなかったけど、golang 使わずに C#だけで作ったら NamedPipe の使い方がよくわからず躓いたのでメモ代わりに記事を書く。

登場人物は3人、TargetClientServer

Client 部分はほとんど 以前の記事(http://bamch0h.hatenablog.com/entry/2018/12/26/012124) と変わらない。

Server 部分は今回新規に書き起こした。 JsonRpc.Attach の第二引数に RPC用のクラス Target を指定することで、public メソッドを公開してくれるようだ。他にも色々公開の仕方があるみたいだけど、今回は割愛。

ServerAttach の次に、rpc.Completion でタスクの終了を待っている。これをしないと、Clientが要求を投げるとServer側がすぐさま終了してしまうようだった。応答を返して、Clientがちゃんとパイプをクローズしてくれるまで待つためにこの行を入れている。(これに気付くまでに結構時間が吸われたので辛かった。。。)

このプログラムを実行すると、1+2 の結果である 3 が表示される。

using System;
using System.Threading.Tasks;
using System.IO.Pipes;
using StreamJsonRpc;

namespace ConsoleApp5
{
    public class Target
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
    }

    public class Client
    {
        public async Task Start(string pipename)
        {
            var stream = new NamedPipeClientStream(".", pipename, PipeDirection.InOut, PipeOptions.Asynchronous);
            stream.Connect();
            using (var rpc = JsonRpc.Attach(stream))
            {
                int ret = await rpc.InvokeAsync<int>("Add", 1, 2);
                Console.WriteLine(ret);
            }
        }
    }

    public class Server
    {
        public void Start(string pipename)
        {
            var stream = new NamedPipeServerStream(pipename, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
            stream.WaitForConnection();
            using (var rpc = JsonRpc.Attach(stream, new Target()))
            {
                rpc.Completion.Wait();
            }
        }
    }

    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();
        }
    }
}