利用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>' + 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>' + 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>' + 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客戶端代碼保持不變,測試:
完畢。
總結
以上是生活随笔為你收集整理的利用SignalR进行消息推送(BS及CS模式)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java日期处理 开始时间-结束时间查询
- 下一篇: UVA1493 - Draw a Mes