14.8K Views
March 15, 22
スライド概要
C# Tokyo オンライン LT 大会 2021/01の発表資料
https://csharp-tokyo.connpass.com/event/200125/
WCFのパイプ通信を .NET 5に向けて gRPCへ置き換える話
自己紹介 ID:suusanex( connpass・Twitter・GitHub共通) 名前:須藤圭太 サイエンスパーク株式会社という独立系ソフトウェアベンダーに所属 4年ほど受託開発で、上流から下流まで全部を回す ここ6年ほどは、自社製品開発を担当 Windowsアプリ開発のネタが多い 勉強会もやってます。最近は開けていませんがそのうち再開します https://yokohama-win-dev-tips.connpass.com/ https://sciencepark.connpass.com
WCFのパイプ通信とは何の話? Windowsアプリ開発で、ピンポイントで便利だった実装方法 Windowsサービスとデスクトップアプリで高速な通信をしたい しかも双方向通信したい そのためのパイプ通信を、.NET Frameworkでは WCFで簡単に実装できた WCFらしく、クラスにメソッドを定義して 関数呼び出しの感覚で使える
しかし、WCFは.NET 5で引退 .NET 5ではWCFサーバーを実装出来ないし、今後もサポート予定なし MSも丁寧なドキュメントでgRPCへの移行を促している ASP.NET Core gRPC に WCF を移行する理由 Microsoft Docs https://docs.microsoft.com/ja-jp/aspnet/core/grpc/why-migrate-wcf-to-dotnetgrpc?view=aspnetcore-5.0
gRPCというやつに乗り換えよう! 気になるポイントがいくつかある パイプ通信できる? 関数呼び出しの感覚で使える? 双方向通信できる? .NET Frameworkのクライアントから呼べる? こういう疑問に答えつつ、軽くだけ実装方法を紹介します
パイプ通信できる? できない しかし、localhostでのTCP/IP通信になるので、十分に速いはず 通信セッション開始・通信1回・通信セッション終了までを1セットとして計測 注意:開発環境での雑な実測結果 遜色なし WCF(Pipe) gRPC 初回の通信 0.1s 0.2s 2回目の通信 0.02s 0.005s 10回連続通信 0.2s 0.05s
関数呼び出しの感覚で使える? 近いことはできる 一方的に送るだけなので、戻り値という考え方は無い リクエストとレスポンスをペアで定義すれば良い 使用感はAsyncのメソッドと同じ
双方向通信できる? できる Bidirectional streaming RPC 最初のSubscribeで2つのストリームを作る サーバーとクライアントがそれぞれストリームを読む
.NET Frameworkのクライアントから呼べ る? できる 同じ定義を共有することで、.NET 5のクライアントとも共存可能
いけそう 気になる点は問題なかったので、移行して行けそう 移行していく上での実装方法を軽く紹介します
少し詳しい実装方法 コマンドの定義 WCFのコントラクトの代わりに、protoファイルで定義を書く 色々書き方があるが、下記のようにするとWCFと同じイメージで使える クラス(イメージ) メソッド(イメージ) message UserSesionToServiceRequest { oneof action { RegisterUserSessionRequest RegisterUserSession = 1; GetDataRequestParam GetDataRequest = 2; SendDataResponseParam SendDataResponse = 3; } メソッドのパラメータ(イメージ) } message RegisterUserSessionRequest{ int32 sessionId = 1; }
少し詳しい実装方法 送信側 ProtoファイルからC#のクラスを生成してくれる 開いたストリームにクラスをWriteすると送信になる クラス用のストリーム クラス(イメージ) await m_DuplexStream.RequestStream.WriteAsync(new UserSesionToServiceRequest { RegisterUserSession = new RegisterUserSessionRequest { SessionId = Process.GetCurrentProcess().SessionId } メソッドのパラメータ }); メソッド(イメージ) (イメージ)
少し詳しい実装方法 受信側 ProtoファイルからC#のクラスを生成してくれる 開いたStreamをReadすると、受信したら制御が戻る クラス(イメージ) クラス用のストリーム await foreach (var req in subscribe.RequestStream.ReadAllAsync(cancellationToken)) { switch (req.ActionCase) { case UserSesionToServiceRequest.ActionOneofCase.RegisterUserSession: { var val = req.RegisterUserSession; メソッドのパラメータ (イメージ) メソッド(イメージ)
まとめ 全く同じではないが、WCFに近いイメージでプロセス間通信を実現できる 同期でレスポンスを待つクラスを作れば、影響軽微で差し替えもできそう WCFを使っている人は、 .NET 5に向けて乗り換えを模索していきましょう