shuhelohelo’s blog

Xamarin.Forms多めです.

WPFからSignalRでサーバーとリアルタイム通信

前回はサーバとブラウザ間でSignalRを用いた通信を試してみました.

shuhelohelo.hatenablog.com

今回は,デスクトップアプリケーションからSignalRを使ってサーバーと通信してみます.

チュートリアルは以下の公式サイトが参考になるでしょう.

docs.microsoft.com

環境

書き方などはブラウザでやったのとほとんど同じです.

まずはNugetでMicrosoft.AspNetCore.SignalR.Clientをインストールします.

次にHubConnectionのインスタンスを作成します.

        public MainWindow()
        {
            InitializeComponent();

            //接続のためのHubConnectionのインスタンスを作成する.
            connection = new HubConnectionBuilder()
                .WithUrl(@"https://localhost:44350/chathub")//サーバー側でMapHubで指定したURLを指定する.
                .Build();
        }

次にサーバー側から呼び出される処理をHubConnection.Onメソッドを使って登録しておく.

受け取るデータの種類,個数を型引数で指定し,サーバーから呼び出すための名前を指定し,メッセージを受け取ったときの処理を登録します.

下の例はサーバー側からReceive(大文字小文字は関係ない)という名前で呼び出すことができ,引数は文字列(string)一つ.

            //サーバー側から呼び出される処理を定義
            //サーバー側からReceiveを指定して呼び出しがあったときに,
            //登録したDelegateが実行される.
            connection.On<string>("Receive", (message) =>
            {
                //Dispatcher使っている理由は?
                //UIに直接書き込むのであればUIスレッドで行う必要があるため
                this.Dispatcher.Invoke(() =>
                {
                    var newMessage = $"{message}";
                    messagesList.Items.Add(newMessage);
                });
            });

(注意) connection.Onメソッドでの処理の登録はイベントハンドラと同じで累積していきます. 同じ記述が実行されるたびに2つ,3つと累積していくので,同じメッセージが1回で2つ,3つドバっと送られることになります. なのでちゃんと管理しておく必要があります.

特定の登録を削除したい場合はconnection.Remove("Receive")のように処理につけた名前を指定することで一括削除されます

と,これだけ用意すれば,クライアントサーバー間でリアルアイム通信する準備は整いました.

あとは,以下のメソッドでサーバーとSignalRで接続されます.

                await connection.StartAsync();

それでは実行してみましょう.

それぞれのプロジェクトをCtrl+F5で実行します.

ブラウザ側はhttps://localhost:<<port番号>>/index.htmlを開きます.

WPF側は最初に接続ボタンを押して,サーバーと接続します.Connection startedと表示されたら,テキストボックスに文字を入力して送信ボタンを押せば,メッセージが送信されます.

f:id:shuhelohelo:20191008095400p:plain

このようにブラウザ,WPF両方のクライアントにお互いのメッセージが表示されることが確認できます.

おわりに

リアルタイム双方向通信がこんなに簡単にできてしまうなんて素晴らしいですね.

しかも,クライアント側の処理の書き方がC#Javascriptで同じように書けるというのも,開発コストが低くて良いです.

クライアント側の基本的な書き方が,

  1. HubのURLを指定
  2. connection.Onで処理を記述
  3. connection.StartAsyncで開始

ととてもシンプルです.

今後の発展としては以下が考えられます.

  • 接続が切れたときに自動再接続されるようにする
  • stringなどの基本型ではなく任意のオブジェクトを受け渡しする
  • サーバーからのメッセージをReactive Extensionで扱う
  • Azure SignalRを使う

blog.xin9le.net

今回のソースコードGitHubで公開しています. (2019.10.08:修正しました)

github.com