zoukankan      html  css  js  c++  java
  • SignalR的另类实现技巧

    很久之前发表过一篇名为《通过三个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}
    ", 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版本即可。

  • 相关阅读:
    【习题 3-12 UVA
    【习题 3-9 UVA
    【Codeforces Round #299 (Div. 2) E】Tavas and Pashmaks
    分布式ID生成器的解决方案总结
    Spring MVC表单防重复提交
    Spring import配置文件使用占位符
    什么是灰度发布,灰度测试。
    浅析负载均衡的6种算法,Ngnix的5种算法。
    神器,阿里巴巴Java代码检查插件
    去BAT面试完的Mysql面试题总结(55道,带完整答案)
  • 原文地址:https://www.cnblogs.com/zuowj/p/7390791.html
Copyright © 2011-2022 走看看