本文主要是我在剛開始學習 SignalR 的技術總結,網上找的學習方法和例子大多只是翻譯了官方給的一個例子,並沒有給出其他一些經典情況的示例,所以才有了本文總結,我在實現推送簡單的數據后,就想到了如何去推送復雜的數據,以及推送一個實時的圖表數據,文本為我原創,轉載請注明出處:Richard.Hu,先上一堆亂七八糟的說明先:
SignalR的官方地址是: https://www.asp.net/signalr
網上給出例子是一個聊天的例子,官網地址是:https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr
聊天的例子是啥意思呢,就是任何一個瀏覽器客戶端發送數據給服務器之后,服務器收到數據然后群發給所有人。這確實是一個經典的例子,所以這次我的研究就不考慮這種情況了,考慮另一種經典的情況,叫做實時數據推送。這是什么意思呢,意思是你的系統有一些實時數據需要不停的在客戶端顯示,在沒有SignalR的時候,ASP.NET基本只能通過不停的ajax輪詢刷新數據,無論是服務器端還是客戶端,都會帶來極大的性能考驗。
好了,開始今天的學習之旅,我所依賴的開發環境是Visual Studio 2017,如果不是這個IDE,不保證完全正確的。
1. 創建沒有身份驗證的ASP.NET MVC項目


這就完成第一步了,創建好了一個項目。
2. 安裝SignalR組件,通過nuget方式安裝


安裝的過程沒有什么好說的,就是一路無腦安裝就可以了,安裝完成之后就出現了界面說明,這個說明還是值得看看的,原版如下:
Please see http://go.microsoft.com/fwlink/?LinkId=272764 for more information on using SignalR.
Upgrading from 1.x to 2.0
-------------------------
Please see http://go.microsoft.com/fwlink/?LinkId=320578 for more information on how to
upgrade your SignalR 1.x application to 2.0.
Mapping the Hubs connection
----------------------------
To enable SignalR in your application, create a class called Startup with the following:
using Microsoft.Owin;
using Owin;
using MyWebApplication;
namespace MyWebApplication
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
Getting Started
---------------
See http://www.asp.net/signalr/overview/getting-started for more information on how to get started.
Why does ~/signalr/hubs return 404 or Why do I get a JavaScript error: 'myhub is undefined'?
--------------------------------------------------------------------------------------------
This issue is generally due to a missing or invalid script reference to the auto-generated Hub JavaScript proxy at '~/signalr/hubs'.
Please make sure that the Hub route is registered before any other routes in your application.
In ASP.NET MVC 4 you can do the following:
<script src="~/signalr/hubs"></script>
If you're writing an ASP.NET MVC 3 application, make sure that you are using Url.Content for your script references:
<script src="@Url.Content("~/signalr/hubs")"></script>
If you're writing a regular ASP.NET application use ResolveClientUrl for your script references or register them via the ScriptManager
using a app root relative path (starting with a '~/'):
<script src='<%: ResolveClientUrl("~/signalr/hubs") %>'></script>
If the above still doesn't work, you may have an issue with routing and extensionless URLs. To fix this, ensure you have the latest
patches installed for IIS and ASP.NET.
仔細閱讀下,里面說了好多東西,我先大致的說下,等全部演示一遍后,再回來看就印象深刻:
1. 映射Hubs連接,需要創建一個startup類,並粘貼上面的代碼
2. 里面有個SignalR自動生成的代理HUB,在路徑'~/signalr/hubs'里面,然后再ASP.NET MVC5中需要使用
<script src="~/signalr/hubs"></script>
其他的就沒有什么東西了,接下來就改造這個項目了。
3. 改造 Index.cshtml 文件
我們目的很明確,在這里顯示服務器推送的數據,就簡單處理了,其他的一堆東西都不要了
@{
ViewBag.Title = "Home Page";
}
<div id="test">這里即將顯示服務器推送的數據</div>
這時候可以嘗試的運行一下

emmmmmmmmm,談了一堆錯誤,沒關系,那就看看這是什么錯誤,
1. 沒有 OwinStartupAttribute 屬性
2. 沒有 Startup.cs 類
這不就是我們第二步里提到的東西么,那就先按照他的意思這么辦好了
4. 創建 Startup.cs 文件
我們就創建一個類文件,放的位置就是項目的下面,然后復制代碼

然后,粘貼下面的代碼,反正官方就是這么要求的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup( typeof( WebApplication1.Startup ) )]
namespace WebApplication1
{
public class Startup
{
public void Configuration( IAppBuilder app )
{
// 有關如何配置應用程序的詳細信息,請訪問 http://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR( );
}
}
}
然后我們在運行看看效果:

哈哈,看到可以了,接下來就准備真的數據推送了。
4. 創建 MyHub.cs 文件
我們就創建一個文件夾,Hubs然后再添加一個文件,就命名成 MyHub.cs

然后把下面的代碼拷貝進去:
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
namespace WebApplication1.Hubs
{
[HubName( "myHub" )]
public class MyHub : Hub
{
// Is set via the constructor on each creation
private Broadcaster _broadcaster;
public MyHub( )
: this( Broadcaster.Instance )
{
}
public MyHub( Broadcaster broadcaster )
{
_broadcaster = broadcaster;
}
}
/// <summary>
/// 數據廣播器
/// </summary>
public class Broadcaster
{
private readonly static Lazy<Broadcaster> _instance =
new Lazy<Broadcaster>( ( ) => new Broadcaster( ) );
private readonly IHubContext _hubContext;
private Timer _broadcastLoop;
public Broadcaster( )
{
// 獲取所有連接的句柄,方便后面進行消息廣播
_hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>( );
// Start the broadcast loop
_broadcastLoop = new Timer(
BroadcastShape,
null,
1000,
1000 );
}
private Random random = new Random( );
private void BroadcastShape( object state )
{
// 定期執行的方法
}
public static Broadcaster Instance
{
get
{
return _instance.Value;
}
}
}
}
里面已經包含了一個Hub集線器了,然后設置了一個統一的靜態 Broadcaster 數據廣播對象,之后我們要進行的操作都在 private void BroadcastShape( object state ) 方法里操作就可以了,現在我們要推送一個隨機數,0-1000的隨機數,然后方法怎么寫呢,參照下面
private void BroadcastShape( object state )
{
// 定期執行的方法
_hubContext.Clients.All.sendTest1( random.Next( 1000 ).ToString( ) );
}
OK,那么我們服務器端已經寫完了,接下來要在客戶端顯示了,回到 index.cshtml 的頁面上看看
@{
ViewBag.Title = "Home Page";
}
<div id="test">這里即將顯示服務器推送的數據</div>
@section scripts {
<script src="~/Scripts/jquery.signalR-2.2.3.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
$(function () {
var mypush = $.connection.myHub;
mypush.client.sendTest1 = function (message) {
$("#test").text(message);
console.log(message);
};
$.connection.hub.start();
});
</script>
}
這里的兩個js庫都是必須引用的,特別是第二個,前面的文檔是已經說明了,下面的js代碼就是獲取hub代理,然后綁定消息。然后就可以運行了。
注意第一個引用的JS,jquery.signalR-2.2.3.min.js 這里面有個版本號信息,需要和你安裝的版本號對應,不然就找不到這個js了,如果你安裝了2.3.0版本,那么這里就要寫jquery.signalR-2.3.0.min.js

可以看到這個值確實是變了,我們再點擊F12看看里面的東西,發現確實有hubs.js文件存在,里面包含了myhub的代理。
5. 推送JSON數據
上面已經演示了一個推送字符串的操作了,如果我們要推送一個復雜的數據怎么辦,我們以一個徽章顯示作為示例
服務器的代碼:
private void BroadcastShape( object state )
{
JObject json = new JObject( );
json.Add( "A", random.Next( 1000, 10000 ).ToString( ) );
json.Add( "B", random.Next( 20 ).ToString( ) );
// 定期執行的方法
_hubContext.Clients.All.sendTest1( json );
}
Index.cshtml代碼
@{
ViewBag.Title = "Home Page";
}
<button class="btn btn-primary" type="button" id="test1">
Messages <span class="badge" id="test2">4</span>
</button>
@section scripts {
<script src="~/Scripts/jquery.signalR-2.2.3.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
$(function () {
var mypush = $.connection.myHub;
mypush.client.sendTest1 = function (json) {
$("#test1").html(json.A + '<span class="badge">' + json.B+'</span>');
console.log(message);
};
$.connection.hub.start();
});
</script>
}
然后再運行,發現:

發現這個還不夠過癮,我想動態顯示圖表怎么辦,比如說柱形圖
6. 實時柱形圖
柱形圖的插件我們選擇開源的 echart 圖表,百度的作品,非常給力,官網地址:http://echarts.baidu.com/ 下面隨便放點這個插件的圖表示例

我們下載這個js文件,

然后把這個js文件添加到項目中去,就如下面一樣

然后修改服務器的推送方法
private void BroadcastShape( object state )
{
int[] values = new int[10];
for (int i = 0; i < values.Length; i++)
{
values[i] = random.Next( 100 );
}
// 定期執行的方法
_hubContext.Clients.All.sendTest1( values );
}
修改客戶端的Index.cshtml代碼
@{
ViewBag.Title = "Home Page";
}
<div id="test" style="height:600px"></div>
@section scripts {
<script src="~/Scripts/jquery.signalR-2.2.3.min.js"></script>
<script src="~/Scripts/echarts.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
$(function () {
var myChart1 = echarts.init(document.getElementById('test'));
myChart1.setOption({
title: {
text: '實時數據加載示例'
},
tooltip: {},
legend: {
data: ['銷量']
},
xAxis: {
data: ["襯衫", "羊毛", "雪紡", "褲子", "高跟", "襪子", "袖子", "領子", "襪子", "腦子"]
},
yAxis: {},
series: [{
name: '銷量',
type: 'bar',
data: []
}]
});
var mypush = $.connection.myHub;
mypush.client.sendTest1 = function (array) {
myChart1.setOption({
series: [{
data: array
}]
});
console.log(array);
};
$.connection.hub.start();
});
</script>
}
然后就可以運行程序看到想要的效果了。

可以看懂動態變化的圖表數據了,其他的動態圖表也是類似的,參照這個就可以實現了,思路都是一致的。文本就到這里為止。
