C#でSignalRを使用した通信を行いたい その9(連続したサーバメソッド呼び出し) | プログラミングがわからなすぎる

プログラミングがわからなすぎる

気が向いた時の備忘録。プログラミングは好きなのに物凄く単純なものしか理解できないからメモしていくうちに覚えられたらいいな

クライアントからサーバメソッドを呼び出す際にMicrosoftのページを見て作っていたら

クライアントからサーバのメソッドを呼び出す際にちょっと困ったことになったのでメモ

(そもそも参考ページをあまり理解していないせいかもしれない)

 

以下参考にしたページです

「ASP.NET SignalR Hubs API ガイド - .NET クライアント (C#)」

 

クライアント側のプロジェクト 

今回実行したいのは、この「メソッドAB呼出」ボタンです

ボタンを押したときに、サーバ側にあるメソッドAとメソッドBを連続して呼び出します

 

 ClientForm.cs

using System;
using System.Windows.Forms;

namespace SignalRClientTest
{
    public partial class ClientForm : Form
    {
        public ClientForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 接続ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ConnectButton_Click(object sender, EventArgs e)
        {
            bool result = SignalRClient.Connect();
            if (result)
                MessageBox.Show("接続成功");
            else
                MessageBox.Show("接続失敗");
        }

        /// <summary>
        /// 切断ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DisConnectButton_Click(object sender, EventArgs e)
        {
            SignalRClient.DisConnect();
        }

        private void CallAB_Click(object sender, EventArgs e)
        {
            TalkRichTextBox.Text += SignalRClient.CallMethodA();
            TalkRichTextBox.Text += SignalRClient.CallMethodB();
        }

    }
}

 

「メソッドAB呼出」ボタンの押下で上記のCallAB_Clickメソッドを実行します

画面に配置されたリッチテキストボックスに、CallMethodAとCallMethodBの戻り値が

表示される想定です

 

 SignalRClientTest.cs

using Microsoft.AspNet.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace SignalRClientTest
{
    class SignalRClient
    {
        private static HubConnection hub;
        private static IHubProxy proxy;
        private const string URL = "http://localhost:8088";
        private const string HUB_CLASS = "TestHub";

        /// <summary>
        /// 接続処理
        /// </summary>
        /// <returns>結果 true:成功 false:失敗</returns>
        public static bool Connect()
        {
            try
            {
                hub = new HubConnection(URL);
                proxy = hub.CreateHubProxy(HUB_CLASS);

                hub.Start().Wait(); // 接続実行
            }
            catch
            {
                // 接続失敗
                return false;
            }
            return true;
        }

        /// <summary>
        /// 切断処理
        /// </summary>
        public static void DisConnect()
        {
            hub?.Stop();
            hub?.Dispose();
        }

        public static string CallMethodA()
        {
            string retStr = proxy.Invoke<string>("MethodA").Result;
            return retStr;
        }
        public static string CallMethodB()
        {
            string retStr = proxy.Invoke<string>("MethodB").Result;
            return retStr;
        }

    }
}

 

参考ページ記載の

戻り値を持ち、複合型パラメーターを受け取るメソッドを同期メソッドで呼び出すクライアント コード

を動かしてみます

 

proxy.Invokeに「.Result」を付与して戻り値を返却してくれるサーバメソッドを呼び出します

 

サーバ側のプロジェクト 

 

サーバ側はとりあえずハブクラスだけ記載します

 

 TestHub.cs

using Microsoft.AspNet.SignalR;

namespace SignalRServerTest
{
    public class TestHub : Hub
    {
        public string MethodA()
        {
            return "A";
        }

        public string MethodB()
        {
            return "B";
        }

    }
}

 

MethodAが呼び出されたら「A」という文字が返却される

MethodBが呼び出されたら「B」という文字が返却される

という非常にシンプルなものになっています

 

期待する結果としては、

クライアント側で「メソッドAB呼出」ボタンをクリックすると

リッチテキストボックスに「AB」と表示される動作となります

 

動かしてみる 

サーバとクライアントを実行してサーバを開始、クライアントから接続までしておきます

 

「メソッドAB呼出」ボタンをクリックしてみました

リッチテキストボックスには「A」しか表示されていません

ちなみにこのときクライアント側のウィンドウで、カーソルがくるくる(砂時計)していました

メソッドBの戻り値が返ってこない…

 

ブレークポイントを貼ってステップ実行してみます

MethodAの呼び出しは通ったので、MethodAは無事呼べたようです

 

次にMethodBの呼び出しに移ります

 

どっかいっちゃいました

この「proxy.Invoke<string>("MethodB").Result」を実行したら

カーソルがくるくるしてずっと待つ羽目になるようです

 

ちなみにサーバ側のMethodBにもブレークポイントを貼っていたのですが

止まらなかったので呼び出されてもいないようです

 

ちゃんと2つとも呼び出される奴に直す 

 

 ClientForm.cs

using System;
using System.Windows.Forms;

namespace SignalRClientTest
{
    public partial class ClientForm : Form
    {
        public ClientForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 接続ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ConnectButton_Click(object sender, EventArgs e)
        {
            bool result = SignalRClient.Connect();
            if (result)
                MessageBox.Show("接続成功");
            else
                MessageBox.Show("接続失敗");
        }

        /// <summary>
        /// 切断ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DisConnectButton_Click(object sender, EventArgs e)
        {
            SignalRClient.DisConnect();
        }

        private async void CallAB_Click(object sender, EventArgs e)
        {
            TalkRichTextBox.Text += await SignalRClient.CallMethodA();
            TalkRichTextBox.Text += await SignalRClient.CallMethodB();
        }
    }
}

 

CallAB_Clickメソッドにasyncをつけます

 

MethodAとMethodBを呼び出してくれるメソッドに

awaitをくっつけて、呼出処理を待ってもらいます

 

 SignalRClientTest.cs

using Microsoft.AspNet.SignalR.Client;
using System.Threading.Tasks;

namespace SignalRClientTest
{
    class SignalRClient
    {
        private static HubConnection hub;
        private static IHubProxy proxy;
        private const string URL = "http://localhost:8088";
        private const string HUB_CLASS = "TestHub";

        /// <summary>
        /// 接続処理
        /// </summary>
        /// <returns>結果 true:成功 false:失敗</returns>
        public static bool Connect()
        {
            try
            {
                hub = new HubConnection(URL);
                proxy = hub.CreateHubProxy(HUB_CLASS);

                hub.Start().Wait(); // 接続実行
            }
            catch
            {
                // 接続失敗
                return false;
            }
            return true;
        }

        /// <summary>
        /// 切断処理
        /// </summary>
        public static void DisConnect()
        {
            hub?.Stop();
            hub?.Dispose();
        }

        public static async Task<string> CallMethodA()
        {
            string retStr = await proxy.Invoke<string>("MethodA");
            return retStr;
        }
        public static async Task<string> CallMethodB()
        {
            string retStr = await proxy.Invoke<string>("MethodB");
            return retStr;
        }
    }
}

 

こちらも非同期メソッドにします

proxy.Invokeから「.Result」を削除して

awaitをくっつけて処理を待ってもらいます

 

直したやつを動かしてみる 

「メソッドAB呼出」ボタンをクリックすると

リッチテキストボックスに「AB」と表示されました

想定通りの結果となったので成功です

 

連続してサーバメソッドをクライアントから呼び出すメモ 

よくわからないけど.Resultを付与して同期メソッドで呼び出すと

1つめのメソッドはちゃんと呼び出されるが

2つ目のメソッドからうまく呼び出されなくなる

 

サーバメソッドを連続して呼び出す際には

非同期メソッドで呼び出す必要がある