創建項目 創建一個空的 Web 項目,併在 Nuget 裡面添加 SignalR,jQuery UI 包,添加以後項目里包含了 jQuery,jQuery.UI ,和 SignalR 的腳本。 創建基礎應用 添加一個 SignalR Hub 類,並命名為 MoveShapeHub ,更新代碼。 當程 ...
創建項目
創建一個空的 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
參考鏈接: