創建項目
創建一個空的 Web 項目,並在 Nuget 里面添加 SignalR,jQuery UI 包,添加以后項目里包含了 jQuery,jQuery.UI ,和 SignalR 的腳本。
創建基礎應用
添加一個 SignalR Hub 類,並命名為 MoveShapeHub ,更新代碼。
using Microsoft.AspNet.SignalR; using Newtonsoft.Json; namespace SignalRDemo3 { public class MoveShapeHub : Hub { public void UpdateModel(ShapeModel clientModel) { clientModel.LastUpdatedBy = Context.ConnectionId; // Update the shape model within our broadcaster Clients.AllExcept(clientModel.LastUpdatedBy).updateShape(clientModel); } } public class ShapeModel { // We declare Left and Top as lowercase with // JsonProperty to sync the client and server models [JsonProperty("left")] public double Left { get; set; } [JsonProperty("top")] public double Top { get; set; } // We don't want the client to get the "LastUpdatedBy" property [JsonIgnore] public string LastUpdatedBy { get; set; } } }
當程序啟動的時候啟動Hub
添加 Owin 類,並在里面配置 SignalR
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(SignalRDemo3.Startup))] namespace SignalRDemo3 { public class Startup { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888 app.MapSignalR(); } } }
添加客戶端
添加一個名為 Index 的 html 頁面,並設置為啟動頁面。
<!DOCTYPE html> <html> <head> <title>SignalR MoveShape Demo</title> <style> #shape { width: 100px; height: 100px; background-color: #FF0000; } </style> </head> <body> <script src="Scripts/jquery-3.1.1.min.js"></script> <script src="Scripts/jquery-ui-1.12.1.min.js"></script> <script src="Scripts/jquery.signalR-2.2.2.js"></script> <script src="/signalr/hubs"></script> <script> $(function () { var moveShapeHub = $.connection.moveShapeHub, $shape = $("#shape"), shapeModel = { left: 0, top: 0 }; moveShapeHub.client.updateShape = function (model) { shapeModel = model; $shape.css({ left: model.left, top: model.top }); }; $.connection.hub.start().done(function () { $shape.draggable({ drag: function () { shapeModel = $shape.offset(); moveShapeHub.server.updateModel(shapeModel); } }); }); }); </script> <div id="shape" /> </body> </html>
上面的 Html 和 JavaScript 代碼創建一個名為 Shape 的 Div ,並且通過jQuery庫給 Shape 提供了拖拽功能,並通過拖拽事件向服務器發送 Shape 的當前位置。
現在可以 F5 啟動調試看效果,當程序啟動以后,打開另一個瀏覽器窗口,輸入地址,你可以在一個窗口拖拽紅色的 Shape,另一個窗口的 Shape 也會跟着動。
添加客戶端循環
如果每次鼠標移動都發送數據到服務端,那就需要很多網絡流量,我們必須降低發送數據的頻率。我們可以通過 setInterval 函數,設置一個固定的時間來發送數據到服務器。
<!DOCTYPE html> <html> <head> <title>SignalR MoveShape Demo</title> <style> #shape { width: 100px; height: 100px; background-color: #FF0000; } </style> </head> <body> <script src="Scripts/jquery-3.1.1.min.js"></script> <script src="Scripts/jquery-ui-1.12.1.min.js"></script> <script src="Scripts/jquery.signalR-2.2.2.js"></script> <script src="/signalr/hubs"></script> <script> $(function () { var moveShapeHub = $.connection.moveShapeHub, $shape = $("#shape"), // Send a maximum of 2 messages per second // (mouse movements trigger a lot of messages) messageFrequency = 2, // Determine how often to send messages in // time to abide by the messageFrequency updateRate = 1000 / messageFrequency, shapeModel = { left: 0, top: 0 }, moved = false; moveShapeHub.client.updateShape = function (model) { shapeModel = model; $shape.css({ left: model.left, top: model.top }); }; $.connection.hub.start().done(function () { $shape.draggable({ drag: function () { shapeModel = $shape.offset(); moved = true; } }); // Start the client side server update interval setInterval(updateServerModel, updateRate); }); function updateServerModel() { // Only update server if we have a new movement if (moved) { moveShapeHub.server.updateModel(shapeModel); moved = false; } } }); </script> <div id="shape" /> </body> </html>
可以用上面的代碼更新剛才的 Index.html頁面,然后F5調試,可以發現現在拖動一個 Shape 以后在另一個瀏覽器里的 Shape 半秒鍾才會更新。
增加服務端循環
更新 MoveShapeHub.cs
using Microsoft.AspNet.SignalR; using Newtonsoft.Json; using System; using System.Threading; namespace SignalRDemo3 { public class Broadcaster { private readonly static Lazy<Broadcaster> _instance = new Lazy<Broadcaster>(() => new Broadcaster()); // We're going to broadcast to all clients once 2 second private readonly TimeSpan BroadcastInterval = TimeSpan.FromMilliseconds(2000); private readonly IHubContext _hubContext; private Timer _broadcastLoop; private ShapeModel _model; private bool _modelUpdated; public Broadcaster() { // Save our hub context so we can easily use it // to send to its connected clients _hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>(); _model = new ShapeModel(); _modelUpdated = false; // Start the broadcast loop _broadcastLoop = new Timer( BroadcastShape, null, BroadcastInterval, BroadcastInterval); } public void BroadcastShape(object state) { // No need to send anything if our model hasn't changed if (_modelUpdated) { // This is how we can access the Clients property // in a static hub method or outside of the hub entirely _hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model); _modelUpdated = false; } } public void UpdateShape(ShapeModel clientModel) { _model = clientModel; _modelUpdated = true; } public static Broadcaster Instance { get { return _instance.Value; } } } public class MoveShapeHub : Hub { // Is set via the constructor on each creation private Broadcaster _broadcaster; public MoveShapeHub() : this(Broadcaster.Instance) { } public MoveShapeHub(Broadcaster broadcaster) { _broadcaster = broadcaster; } public void UpdateModel(ShapeModel clientModel) { clientModel.LastUpdatedBy = Context.ConnectionId; // Update the shape model within our broadcaster _broadcaster.UpdateShape(clientModel); } } public class ShapeModel { // We declare Left and Top as lowercase with // JsonProperty to sync the client and server models [JsonProperty("left")] public double Left { get; set; } [JsonProperty("top")] public double Top { get; set; } // We don't want the client to get the "LastUpdatedBy" property [JsonIgnore] public string LastUpdatedBy { get; set; } } }
上面的代碼新建了一個 Broadcaster 類,通過類 Timer 來進行節流。
因為 Hub 實例每次都會重新創建,所以只能創建一個 Broadcaster 的單例模型。調用客戶端 UpdateShape 的方法被移出了 hub 。現在它通過類 Broadcaster 來管理,通過名為 _broadcastLoop 的 timer 每兩秒更新一次。
最后因為不能直接在 hub 里調用客戶端方法,類 Broadcaster 需要通過 GlobalHost 來獲取到當前進行操作的 hub。
最終使用 F5 進行調試,雖然客戶端設置了半秒一次的刷新,但是因為服務器端設置了2秒一次刷新,所以你在當前瀏覽器里移動 Shape ,兩秒鍾過后另一個瀏覽器里的 Shape 才會移動到當前位置。
源代碼鏈接:
鏈接: https://pan.baidu.com/s/1o8NXwTW 密碼: 5r5i
參考鏈接: