• 利用SignalR进行消息推送(BS及CS模式)


    最近项目中需要使用SignalR,在此记录自己初次使用时候的一些问题,避免以后再踩。

    主要测试三种模式,BS:客户端及服务端均在web中来实现。CS 客户端与服务器端均采用winform的形式。bs和cs混合,服务器端采用winform,客户端采用web和winrorm两种模式。

    一、BS

    S:创建一个类mvcfhub,继承Hub。当然,此时需要先在NuGet中获取SignalR,如下图:

     public class mvcfhub : Hub
    {
    //将服务端方法Hello重新命名为sendone,
    [HubMethodName("sendone")] public void Hello(string message, string connectionid) { if (connectionid != null) { //调用客户端方法 Clients.Client(connectionid).SendMessage("ID:" + connectionid, message + " 时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); } else { Clients.All.SendMessage("ID:" + connectionid, message + " 时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); } }
    }

    安装Mictosoft.ASP.NET.SignalR,使用的是2.4.0版本。

    在安装此控件的同时会自动添加 用于web端的js文件。当然此时也会添加owin及其他依赖项,这些都会在安装上面的dll的时候自动安装。

    待上述dll安装完毕后,再创建 owin startup 类,(这个需要再研究...)

    代码如下:

    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;

    [assembly: OwinStartup(typeof(MVCF.Startup))]

    namespace MVCF
    {
    public class Startup
    {
    public void Configuration(IAppBuilder app)
    {

    app.MapSignalR();

    }

    }
    }

    至此,服务器端的简单Hub类创建完成。

    web客户端:

     首先需要引用signalR 的js文件,我使用的是MVC bundles经行加载。

                //signalR
                bundles.Add(new ScriptBundle("~/bundles/signalR/js").Include("~/Scripts/jquery.signalR-2.4.0.js"));

    关键步骤:需要额外再引用自动生成的代理js

       <script src="~/signalr/hubs"></script>,后面在cs于bc混合里面,会再提到,和此处有些区别。

    创建页面signalR.cshtml

    @{
        ViewBag.Title = "signalR";
        Layout = null;
    }
    <h2>signalR<label id="rstart"></label></h2>
    <div>
        当前在线人数:<label id="users"></label>
        <select id="userslist"></select>
        <label id="messageBox"></label>
        <input type="text" id="message" />
        <input type="button" id="sendmessage" value="发送" />
        <input type="button" id="stopsignalr" value="断开连接" />
        <input type="button" id="startsignalr" value="重新连接" />
    </div>
    <script>
        $(document).ready(function () {
            console.log("a")
            //引用自动生成的集线器代理
            var chat = $.connection.mvcfhub;
            chat.client.status = function (status) {
                $("#rstart").text('');
                if (status)
                    $("#rstart").text('在线');
    
            }
            chat.client.getusers = function (userslist) {
                var selectlist = "";
                $("#users").text('');
                $("#users").append(userslist.length);
                $.each(userslist, function (index, name) {
                    selectlist += "<option value=" + userslist[index] + ">" + userslist[index] + "</option>";
                });
                $("#userslist").html("");
                $("#userslist").append(selectlist);
            }
    
            //定义服务器调用的客户端sendMessage来显示新消息
            chat.client.SendMessage = function (name, message) {
                //向页面添加消息
                $("#messageBox").append('<li><strong style="color:green">' + name + '</strong>:' + message + '</li>');
            }
            $.connection.hub.connectionSlow(function () {
                console.log("连接出问题了!");
            });
            /*重新连接*/
            //$.connection.hub.disconnected(function () {
            //    setTimeout(function () {
            //        $.connection.hub.start().done(function () {
            //            console.log("重新连接成功!")
            //        });
            //    }, 5000); // Restart connection after 5 seconds.
            //});
            // 开始连接服务器
            var hubid = "";
            $.connection.hub.start().done(function () {
                hubid = $.connection.hub.id;
                chat.server.userlist();
                $('#sendmessage').on('click', function () {
                    //调用服务器端集线器的Send方法
                    chat.server.sendone($('#message').val(), $("#userslist").val());
                    //清空输入框信息并获取焦点
                    $("#message").val('').focus();
                });
            });
            $("#stopsignalr").click(function () {
                $.connection.hub.stop(hubid);
            });
            $("#startsignalr").click(function () {
                $.connection.hub.start();
            });
        });
    
    
           
            //$.connection.hub.url = "http://localhost:8889/signalr";
            //var chat = $.connection.myhub;
            //chat.client.addMessage = function (name, message) {
            //    //向页面添加消息
            //    $("#messageBox").append('<li><strong style="color:green">' + name + '</strong>:' + message + '</li>');
            //}
            //    // 开始连接服务器
            //    var hubid = "";
            //    $.connection.hub.start().done(function () {
            //        hubid = $.connection.hub.id;
                 
            //        $('#sendmessage').on('click', function () {
            //            //调用服务器端集线器的Send方法
            //            chat.server.send( hubid,$('#message').val());
            //            //清空输入框信息并获取焦点
            //            $("#message").val('').focus();
            //        });
            //    });
            //    $("#stopsignalr").click(function () {
            //        $.connection.hub.stop(hubid);
            //    });
            //    $("#startsignalr").click(function () {
            //        $.connection.hub.start();
            //    });
     
    </script>
    View Code

    测试结果:

    二、CS:

    利用winform来做服务端,需要额外安装如下dll,

    Microsoft.Owin.Cors

    Microsoft.Owin.Hosting

    Microsoft.AspNet.SignalR.Client

     创建 owin startup 类

    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;
    using Microsoft.Owin.Cors;
    
    [assembly: OwinStartup(typeof(SignalR_monitoring.Startup))]
    
    namespace SignalR_monitoring
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
              
                app.UseCors(CorsOptions.AllowAll);
                app.MapSignalR();
            }
        }
    }

    创建Hub类,参考BS:

       public class myhub : Hub
        {
            private static List<Myc> userm;
            public void Send(string name, string message)
            {
                //客户端调用的方法
                Clients.All.addMessage(name, message);
            }
            //服务器端
            public void testsend(string id, string message)
            {
                //客户端调用方法
                Clients.Client(id).mysend(message);
            }
            public void Send2(Myc mc)
            {
                mc.name = Context.ConnectionId;
                //调用前端代码
                // Clients.Client(Context.ConnectionId).sendmessage(Context.ConnectionId,message);
                Clients.All.sendmessage(mc);
            }
           
            /// <summary>
            /// 客户端连接服务器成功后调用
            /// </summary>
            /// <returns></returns>
            public override Task OnConnected()
            {
                if (userm == null)
                {
                    userm = new List<Myc>();
                }
                userm.Add(new Myc { id = Context.ConnectionId, status = true ,t=DateTime.Now});
                Clients.All.onlineuser(userm.ToList());
                // 在这添加你的代码.   
                // 例如:在一个聊天程序中,记录当前连接的用户ID和名称,并标记用户在线.
                // 在该方法中的代码完成后,通知客户端建立连接,客户端代码
                // start().done(function(){//你的代码});
                return base.OnConnected();
            }
            /// <summary>
            /// 客户端断开连接后调用
            /// </summary>
            /// <param name="stopcalled"></param>
            /// <returns></returns>
            public override Task OnDisconnected(bool stopcalled)
            {
                if (userm == null)
                {
                    userm = new List<Myc>();
                }
                userm.Remove((from u in userm where u.id == Context.ConnectionId select u).ToList()[0]);
                Clients.All.onlineuser(userm.ToList());
                // 在这添加你的代码.
                // 例如: 标记用户离线 
                // 删除连接ID与用户的关联.
                return base.OnDisconnected(stopcalled);
            }
    
        }

    public class Myc
    {
    public string id { get; set; }
    public string name { get; set; }
    public bool status { get; set; }
    public DateTime t { get; set; }
    }

     

    创建一个winform,做为启动服务的窗口

       public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
            public IDisposable SignalR2 { get; set; }
            private const string ServerUri2 = "http://localhost:8889"; // SignalR服务地址,自定义
            private void button1_Click(object sender, EventArgs e)
            {
                Task.Run(() => { StartServer(); }); // 异步启动SignalR服务
                label2.Text = "服务启动成功" + ServerUri2;
            }
            private bool StartServer()
            {
                try
                {
                    
                    
                    SignalR2 = WebApp.Start(ServerUri2);
    /*下面代码是为了获取当前连接的客户端信息*/
    //获取连接客户端信息 HubConnection connection = new HubConnection(ServerUri2); IHubProxy rhub = connection.CreateHubProxy("myhub"); connection.Start();//连接服务器 rhub.On<List<Myc>>("onlineuser", onlienuser); } catch (Exception ex) { return false; } return true; } private bool StopServer() { try { SignalR2.Dispose(); } catch (Exception ex) { return false; } return true; } public void onlienuser(List<Myc> ou) { Thread viewthread = new Thread(viewincrease); viewthread.Start(ou); } public void viewincrease(object obj1) { List<Myc> obj = obj1 as List<Myc>; if (label1.InvokeRequired) { Action<string> label = (x) => { this.label1.Text = obj.Count.ToString(); }; label1.Invoke(label, obj.Count.ToString()); } if (listBox1.InvokeRequired) { Action<string> listb = (x) => { this.listBox1.Items.Clear(); }; listBox1.Invoke(listb, ""); foreach (Myc m in obj) { Action<string> listbox = (x) => { this.listBox1.Items.Add("id:" + m.id + " status:" + m.status+" T:"+m.t); }; listBox1.Invoke(listbox, "id:" + m.id + " status:" + m.status + " T:" + m.t); } } } private void button2_Click(object sender, EventArgs e) { label2.Text = "关闭"; Task.Run(() => { StopServer(); }); } }

    其中 “onlineuser”方法名必须用hub类中的OnConnected 方法的 客户端方法名一致。

    下面我们来创建一个客户端,向服务端发送消息

     

    代码如下:

     public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            HubConnection connection = null;
            IHubProxy rhub = null;
            private const string ServerUri = "http://localhost:8889";
            private void button1_Click(object sender, EventArgs e)
            {
                connection = new HubConnection(ServerUri);
                //类名必须与服务端一致
                //myHub = connection.CreateHubProxy("BroadcastHub");                  
                rhub = connection.CreateHubProxy("myhub");
                connection.Start();//连接服务器  
                label1.Text = "连接服务器成功!";
                //注册客户端方法名称"addMessage"与服务器端Send方法对应,对应的 callback方法 ReceiveMsg
                rhub.On<string, string>("addMessage", ReceiveMsg);
            }
            /// <summary>
            /// 对应的callback方法
            /// </summary>
            /// <param name="name"></param>
            /// <param name="message"></param>
            private void ReceiveMsg(string name, string message)
            {
                Thread viewthread = new Thread(viewincrease);
                viewthread.Start("id:" + name + " M:" + message+" Date:"+DateTime.Now);
            }
            /// <summary>
            /// 发送消息
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button3_Click(object sender, EventArgs e)
            {
                string m = textBox1.Text;
                string id = connection.ConnectionId;
                //调用 hub中的方法 Send
                rhub.Invoke("Send", id,m).Wait();
            }
    
           
            public void viewincrease(object obj)
            {
                string message = obj as string;
                if (listBox1.InvokeRequired)
                {
                    Action<string> listbox = (x) => { this.listBox1.Items.Add(message); };
                    listBox1.Invoke(listbox, message);
                }
            }
        }

    开始测试

    启动服务

    显示1个客户端连接。

    打开另外一个客户端

     测试完成。连接数为2,客户端发送test,然后接收到test信息。

    三、CS BS 混合

    服务端保持不变,web端的js引用需要修改,带上服务器地址信息,web端修改如下:

    web端的引用改为服务端地址。

    web页面 js部分:

            $.connection.hub.url = "http://localhost:8889/signalr";
            var chat = $.connection.myhub;
            chat.client.addMessage = function (name, message) {
                //向页面添加消息
                $("#messageBox").append('<li><strong style="color:green">' + name + '</strong>:' + message + '</li>');
            }
                // 开始连接服务器
                var hubid = "";
                $.connection.hub.start().done(function () {
                    hubid = $.connection.hub.id;
                 
                    $('#sendmessage').on('click', function () {
                        //调用服务器端集线器的Send方法
                        chat.server.send( hubid,$('#message').val());                    
                        $("#message").val('').focus();
                    });
                });
                $("#stopsignalr").click(function () {
                    $.connection.hub.stop(hubid);
                });
                $("#startsignalr").click(function () {
                    $.connection.hub.start();
                });

    winform客户端代码保持不变,测试:

     完毕。

  • 相关阅读:
    java8新特性→方法和构造函数引用:替代Lambda表达式
    java8新特性→Stream流:用于解决已有集合类库既有的弊端
    java8新特性→函数式接口
    java8新特新→Lambda表达式
    子查询
    Vue之监听数据变化watch、computed、methods
    Vue路由-使用命名视图实现经典布局
    Vue路由-使用children属性实现路由
    Vue之路由传参
    Vue路由之touter-link、router-direct的使用
  • 原文地址:https://www.cnblogs.com/daniel-niu/p/10536484.html
Copyright © 2020-2023  润新知