文章出處

很久之前發表過一篇名為《通過三個DEMO學會SignalR的三種實現方式》的文章,在那篇文章里面詳細介紹了在WEB應用下的常用SignalR實現方法,而今天我們來利用SignalR來實現其它的一些用法,比如:B/S 與 C/S互相通訊,比如:C/S與C/S通訊。

一、B/S 與 C/S互相通訊(ASP.NET 向  Winform  廣播消息),先看效果如下:

如上圖所示,采用服務端發送消息(指在C#代碼發送),然后winform接收消息。

如上圖所示,采服客戶端(瀏覽器)JS 代理對象發送消息,然后winform接收消息。

上述示例的實現代碼如下:

ASP.NET 服務端代碼:

MyHub:

    [HubName("myHub")]
    public class MyHub : Hub
    {
        public static Action<string> SendMsgAction = null;
        public MyHub()
        {
            SendMsgAction = new Action<string>(SendMsg);
        }

        private void SendMsg(string msg)
        {
            Clients.All.RecvMsg(msg);
        }

        [HubMethodName("broadcast")]
        public void Broadcast(string msg)
        {
            if ("broadcast".Equals(Context.QueryString["identity"])) //只有帶有廣播者身份才能進行廣播消息
            {
                SendMsg(msg);
            }
        }


        public override System.Threading.Tasks.Task OnConnected()
        {
            return base.OnConnected();
        }

        [HubMethodName("testConnect")]
        public void TestConnect()
        {
            System.Diagnostics.Debug.Write("ddd");
        }
    }

ASP.NET 頁面:(演示就用了服務器控件,以便到服務端進行發送)

        <div>
            廣播消息:<input type="text" id="txtmsg" runat="server"  />
            <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="服務端發送" />
        </div>

ASP.NET CS代碼:

        protected void Button1_Click(object sender, EventArgs e)
        {
            if(MyHub.SendMsgAction!=null)
            {
                MyHub.SendMsgAction("服務端發送消息-" + txtmsg.Value);
            }
        }

 在這里特別說明一下,因為MyHub是有連接時才會生成實例,我們無法直接在服務端獲取到MyHub的實例,所以采取了在MyHub構造函數時,將SendMsg暴露給靜態的 SendMsgAction委托,這樣服務端就可以直接通過判斷SendMsgAction是否有訂閱來決定是否可以發送消息。這是一個取巧的的方式,當然如果大家有更好的方法,歡迎交流。

通過瀏覽器發送實現方法與之前的文章介紹的相同,這里采用代理模式,ASP.NET頁面代碼如下:(不作過多介紹)

    <script src="<%=ResolveUrl("~/Scripts/jquery-1.10.2.min.js") %>" type="text/javascript"></script>
    <script src="<%=ResolveUrl("~/Scripts/jquery.signalR-2.2.2.min.js") %>" type="text/javascript"></script>
    <script src="<%=ResolveUrl("~/signalr/hubs") %>" type="text/javascript"></script>


        <div>
            廣播消息:<input type="text" id="txtmsg2"  />
            <input type="button" id="btnSend" value="客戶端發送" />
        </div>


    <script type="text/javascript">
        $(function () {
           
            var myhub = $.connection.myHub;
            $.connection.hub.qs = { "identity": "broadcast" };
            $.connection.hub.start().done(function () {
                $("#btnSend").click(function () {
                    var msg = $("#txtmsg2").val();
                    myhub.server.broadcast("客戶端發送消息-" + msg)
                    .done(function () {
                        alert("發送成功!");
                    }).fail(function (e) {
                                alert(e);
                                $("#txtmsg2").focus();
                   });
                });
            });

        });
    </script>

 這里有一個注意點:我們在定義MyHub類時,按照CSharp的代碼規范是:類名 及方法名首字母都大寫,但JS自動生成的代理JS類及方法名卻會變成JS的命規范,即:函數名首個字母是小寫,如:MyHub -->myHub,所以為了便于兼容JS調用,在定義Hub類時,用上HubName及HubMethodName特性,指定統一名稱。

winform客戶端接收消息步驟:

1.通過NuGet安裝SignalR.Client相關組件

2.Winform CS代碼:

    public partial class Form1 : Form
    {
        private HubConnection connection = null;
        private IHubProxy hubProxy = null;
        private System.Threading.SynchronizationContext syncContext = null;

        public Form1()
        {
            InitializeComponent();
            syncContext = System.Threading.SynchronizationContext.Current;
        }

        private  void Form1_Load(object sender, EventArgs e)
        {
           CreateHubConnection();
        }

        /// <summary>
        /// 創建Hub代理類,并啟動
        /// </summary>
        private void CreateHubConnection()
        {
            connection = new HubConnection("http://localhost:3510/signalr");//SignalR服務端地址
           hubProxy = connection.CreateHubProxy("MyHub");
           hubProxy.On<string>("RecvMsg", RecvMsg); //訂閱接收消息
           connection.Start().Wait();
        }
        
        /// <summary>
        /// 接收SignalR服務端的消息
        /// </summary>
        /// <param name="msg"></param>
        private void RecvMsg(string msg)
        {
            syncContext.Post((o) => {
                textBox1.Text += string.Format("{0:yyyy-MM-dd HH:mm:ss}{1}\r\n", DateTime.Now, o);
            }, msg);
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            connection.Dispose();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            hubProxy.Invoke("TestConnect");//調用SignalR服務端的方法
        }

    }

 通過上述代碼可以看出,與ASP.NET 頁面生成的JS代理類的方式原理基本相同,都是通過代理類來與服務端進行交互,都是通過HTTP協議進行通訊。

 二、C/S 與 C/S 互相通訊(winform與winform),其實本質上服務端還是B/S,只不過我們采取了SignalR self Host(里面用到了OWIN self Host),也就是將網站寄宿到winform而矣,只是我們通過winform操作更方更而矣,效果如下:

winform服務端實現流程:

1.先通過NuGet 分別安裝Microsoft.AspNet.SignalR、Microsoft.AspNet.SignalR Self Host,如下圖示:

 

2.添加Startup類文件,并在里面添加映射SignalR,代碼如下:(與ASP.NET服務端的Startup代碼相同)

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }

3.編寫OWIN 的寄宿代碼,MyHub與上文中的相同,故不再貼出

    public partial class Form1 : Form
    {
        private IDisposable webHost = null;

        public static Form1 Current = null;

        public Form1()
        {
            InitializeComponent();
            this.Text = "SignalR Winform服務端";
            Current = this;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                webHost = WebApp.Start<Startup>("http://localhost:3512");
                label2.Text = "http://localhost:3512";
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                webHost.Dispose();
            }
            catch
            { }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if(MyHub.SendMsgAction!=null)
            {
                MyHub.SendMsgAction(textBox1.Text);
            }
        }

        public void ShowMsg(string msg)
        {
            this.Invoke(new MethodInvoker(() => {
                listBox1.Items.Add(msg);
            }));
        }
    }

 這里有幾個小細節需要注意:

1.安裝Microsoft.AspNet.SignalR后會在項目中生成Sciprts文件夾,這個在winform項目時就可以刪除掉;

2.安裝Microsoft.AspNet.SignalR Self Host后,編譯可能無問題,但運行起來時,可能會報朱找到匹配的OWin程序集,這個是因為OWIN版本問題,只需單獨再安裝一下指定的OWIN版本即可。

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()