【SignalR學習系列】3. SignalR實時高刷新率程序


創建項目

創建一個空的 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

 

參考鏈接:

https://docs.microsoft.com/zh-cn/aspnet/signalr/overview/getting-started/tutorial-high-frequency-realtime-with-signalr


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM