利用SignalR进行消息推送(B\S及C\S模式)
利用SignalR进行消息推送(B\S及C\S模式)
最近项目中需要使用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客户端代码保持不变,测试:

完毕。






浙公网安备 33010602011771号
麻烦利用SignalR进行消息推送(B\S及C\S模式)
都发我一下谢谢