場景:服務端在背景開啟了一個HttpListener的監聽器來監聽第三方裝置通過http協定發送過來的裝置實時資料,當服務端接收到裝置的實時資料後,通過SignalR技術将資料發送到前端
我們先看服務端添加SignalR元件的步驟吧。
首先我們要從NuGet上查找SignalR元件,安裝以下兩個元件:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL5MjNzIDN1YTMxIDOwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
在目前項目上右擊,添加建立項,找到OWIN Startup類,點選添加。代碼如下:
public void Configuration(IAppBuilder app)
{
// 有關如何配置應用程式的詳細資訊,請通路 https://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR();
}
然後添加建立項,SignalR Hub Class,即添加SignalR的集線器類。集線器類的代碼如下:
[HubName("HubDemo")]
public class HubDemo : Hub
{
private readonly HubDemoService _hubDemoService;
public static HubDemo Instance { get; } = new HubDemo(HubDemoService.Instance);
public HubDemo() : this(HubDemoService.Instance)
{
}
public HubDemo(HubDemoService hubDemoService)
{
_hubDemoService = hubDemoService;
}
public void Hello(string projectID)
{
Groups.Add(Context.ConnectionId, projectID);
_hubDemoService.Hello();
}
public void SendClient(string deviceSN)
{
_hubDemoService.SendClient(deviceSN);
}
}
這裡我們建了一個集線器類的服務類來完成具體的資料發送任務,服務類的代碼如下:
public class HubDemoService
{
private HubDemoService(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
}
private IHubConnectionContext<dynamic> Clients
{
get;
set;
}
public static HubDemoService Instance { get; } = new HubDemoService(GlobalHost.ConnectionManager.GetHubContext<HubDemo>().Clients);
public void Hello()
{
Clients.All.Hello(true);
}
public void SendClient(string deviceSN)
{
Clients.Group(deviceSN).SendClient("裝置資料");
}
}
集線器類和服務類我們都使用的是單例模式。而且我們使用了分組方法,分組的概念就相當于微信群,你發出去的消息隻有這個群的人才能看到,其他人是收不到這個你發的消息的。
下面我們看看怎麼調用集線器類的SendClient方法來主動把資料發送到用戶端。我在Home控制器中添加了一個視圖,這就是一個很簡單的視圖,SignalR的用戶端操作就寫在這個視圖裡面,代碼如下:
public ActionResult SendClient()
{
return View();
}
public string AjaxPost()
{
HubDemo.Instance.SendClient("10000");
return "ajax傳回";
}
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>SendClient</title>
</head>
<body>
<div>
<button id="btn1" onclick="btnclick()">發送請求</button>
</div>
<script src="~/Scripts/jquery-3.4.1.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.2.js"></script>
<script src="~/signalr/hubs"></script>
<script type="text/javascript">
var hubDemo = $.connection.HubDemo;
hubDemo.client.Hello = function (success) {
if (success) {
console.log("初始化連接配接成功!");
}
else {
console.log("初始化連接配接失敗!");
}
}
hubDemo.client.SendClient = function (data) {
console.log(data);
}
$.connection.hub.start().done(function () {
hubDemo.server.hello("10000");
});
function btnclick() {
$.ajax({
url: "/Home/AjaxPost",
type:"GET",
success: function (data) {
}
});
}
</script>
</body>
</html>
要想使用SignalR,必須添加js代碼中的3個js,其中/signalr/hubs是SignalR自動生成的。
在start完成後,我們調用了伺服器的hello方法來把目前裝置序列号發送給服務端,服務端會用這個裝置序列号生成一個分組。當服務端收到這個裝置序列号的資料後,就隻把裝置的資料發送給目前這個用戶端,避免了沒有監聽目前裝置的用戶端也收到這個裝置的資料。
這裡有個地方一定要注意,就是hello這個方法的大小寫問題,雖然服務端的Hello方法H是大寫的,但是在用戶端調用的時候,H必須是小寫,不然用戶端會提示你Hello不是一個方法,如圖:
還有一個問題也要注意,就是我們不能在服務端傳回View()之前發送資料到用戶端,如:
public ActionResult SendClient()
{
HubDemo.Instance.SendClient("10000");
return View();
}
因為服務端傳回View()之後才會對html頁面進行加載,在傳回View()之前調用SendClient,對應的視圖裡面的js代碼都還沒有執行,是以用戶端是收不到資料的。
為了解決這個問題,我在界面上加了一個按鈕,通過點選這個按鈕,發送一個ajax的請求,服務端接收到請求後,再發送裝置資料發送到用戶端。通過按鈕觸發ajax請求這個步驟其實是模拟服務端接收到裝置發送過來的資料。
啟動程式,進入到SendClient,頁面加載完成後,點選發送請求按鈕
用戶端輸出如下: