隐藏

利用SignalR进行消息推送(B\S及C\S模式)

发布:2020/10/28 15:57:29作者:管理员 来源:本站 浏览次数:963

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

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

一、B\S

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>
复制代码

测试结果:

 

二、C\S:

利用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客户端代码保持不变,测试:

 

 完毕。