【问题标题】:How to update asp.net mvc view periodically using signalR?如何使用signalR定期更新asp.net mvc视图?
【发布时间】:2019-03-07 23:13:14
【问题描述】:

现在我使用视图中的定期 ajax 调用来检索新数据。 我需要每 2 秒执行一次。控制器检查一些硬件/传感器信号。

有没有办法使用 signalR 代替 ajax?

我总是发现一个视图的更改会将新数据发送到所有其他视图(如聊天程序)的示例。 我还发现了 signalR 和 sql 依赖关系,但因此我需要将所有数据发送到 sql server。

我还发现那篇文章Realtime Maps Based On XML File Changes With SignalR 他们正在使用“FileSystemWatcher”来检查 xml 文件的更改。 是否可以“构建”另一个“SystemWatcher”来检查我的传感器数据?

【问题讨论】:

    标签: ajax asp.net-mvc signalr


    【解决方案1】:

    控制器是否通过ajax请求触发了硬件/传感器检查?

    由于使用 SignalR,其想法是您有其他东西来生成数据,例如,在聊天应用程序中,用户向控制器发布消息,控制器通过 SignalR 将消息发送给其他客户端。

    在您的情况下,您需要进行硬件/传感器检查。这可能是:

    • 检查硬件/传感器的后台线程
    • 检查传感器并发布到您的 asp.net MVC 应用程序的计划任务

    无论是当您的后台线程检测到更改或您的控制器收到来自计划任务的更新数据的帖子时,您都可以通过 SignalR 向您的客户端发送消息。

    这样您就不会一直让您的客户轮询。但是,您仍然需要定期检查您的传感器数据,除非您的传感器/硬件有一些 push 方法向您发送数据。

    如果您需要自己从传感器中提取数据,而您只有 1 个客户端,那么与仅进行 ajax 轮询相比,您不会从 SignalR 中获得太多好处。但是,如果您有 N 个客户端,您可以获得很大的好处,因为您将只有 1 个线程读取数据并推送到客户端,而不是 N 读取它。

    一旦您弄清楚了在控制器中获取数据的方式,使用 SignalR 将其发送给您的客户端应该与您引用的消息传递示例相同,这些文档应该向您展示如何实现它。

    【讨论】:

    • 您好,硬件/传感器检查由控制器完成,由 ajax 请求触发(每秒)。我有 10 个客户,他们都指向同一个传感器。有没有办法在服务器上运行一个后台任务(作为我的 mvc 应用程序的一部分),将传感器数据发布到客户端(视图)?
    • 因此,您应该继续使用我的回答中描述的 2 个选项之一,例如使用检查硬件/传感器的后台线程。您将每 XX 秒检查一次传感器,如果需要存储数据,并且每当数据发生变化时,通过 SignalR 向客户端发送消息。像Client.All.newSensorData(newValue) 这样的东西。最好在这里描述:docs.microsoft.com/en-us/aspnet/signalr
    • 好的,我会检查文档。对于后台线程,您的意思是由计时器事件触发的函数?您是否有一个如何实现的示例?因为在 MVC 中,控制器通常只在客户端请求后执行任务...
    • 我会在 Application_Start 中启动一个线程。 This blog post 描述了一些选项。如果您使用的是 asp.net core,则可以使用托管服务。
    • 谢谢。我会看看。 Hangfire 看起来真的很有趣,但最短重启时间只有 1 分钟。我可能会尝试 QueueBackgroundWorkItem...
    【解决方案2】:

    现在我有以下解决方案。如果这是一种常见的方式,有人可以检查我的代码吗?或者我会遇到麻烦吗?

    首先我创建了一个集线器类“MyHub.cs” 我必须使用延迟初始化吗? OnReconnected 部分可以吗?

     [HubName("data")]
        public class DataHub : Hub
        {
            List<LineUser> userList = new List<LineUser>();
            public static ConcurrentDictionary<string, LineUser> MyUsers = new ConcurrentDictionary<string, LineUser>();
    
            public override Task OnConnected()
            {
                var context = GlobalHost.ConnectionManager.GetHubContext<DataHub>();
    
                string userConnectionID = Context.ConnectionId;
                MyUsers.TryAdd(Context.ConnectionId, new LineUser() { ConnectionID = Context.ConnectionId });
    
                return base.OnConnected();
            }
    
            public override Task OnReconnected()
            {
                var context = GlobalHost.ConnectionManager.GetHubContext<DataHub>();
    
                string userConnectionID = Context.ConnectionId;
    
                if (MyUsers.TryAdd(Context.ConnectionId, new LineUser() { ConnectionID = Context.ConnectionId }))
                    _userCount++;
    
                var resconnectedUser = new LineUser();
                MyUsers.TryGetValue(userConnectionID, out resconnectedUser);
                Groups.Add(userConnectionID, resconnectedUser.LineNr.ToString());
    
                return base.OnReconnected();
            }
    
            public override Task OnDisconnected(bool stopCalled)
            {
                var context = GlobalHost.ConnectionManager.GetHubContext<DataHub>();
    
                string userConnectionID = Context.ConnectionId;
    
                LineUser garbage;
    
                var disconnectedUser = new LineUser();
                MyUsers.TryGetValue(userConnectionID, out disconnectedUser);
                Groups.Remove(userConnectionID, disconnectedUser.LineNr.ToString());
    
                MyUsers.TryRemove(userConnectionID, out garbage);
    
                return base.OnDisconnected(stopCalled);
            }
    
            [HubMethodName("registerName")]
            public void RegisterConId(int LineNr, string userConnectionID)
            {
                var oldUser = new LineUser();
                var newUser = new LineUser();
                newUser.LineNr = LineNr;
                newUser.ConnectionID = userConnectionID;
                newUser.Connected = true;
    
                MyUsers.TryGetValue(userConnectionID, out oldUser);
    
                MyUsers.TryUpdate(userConnectionID, newUser, oldUser);
    
                Groups.Add(userConnectionID, LineNr.ToString());
            }
    
        }
    

    然后我用 Quartz.net "BackGroundJob.cs" 创建了一个 backgoundjob (这将在应用程序启动后每秒从 JobScheduler 类触发)。 如果有新的传感器数据可用,我将传感器数据发送到特定组(组名将在客户端调用 HubMethodName“registerName”后创建。 因为传感器编号。 6 数据应该只发送给客户端 nr。 6(编号为 6 的所有客户端都在组“6”中)

      public class BackGroundJob : IJob
        {
            //Global variable to save the result between to background job executions
            SensorData oldsensorData = new SensorData();        
    
            public Task Execute(IJobExecutionContext context)
            {
    
                var newSensorData = ReadSensorData();
    
                if (!newSensorData.Equals(oldsensorData))
                {
                    IHubContext hub = GlobalHost.ConnectionManager.GetHubContext<DataHub>();
    
                    result = hub.Clients.Group(newSensorData.LineNr.ToString()).announceToLine("Sensor data for Line: " + newSensorData.LineNr.ToString() + " Temp: " + newSensorData.Temp.ToString());
    
                    //Save new data to global object
                    oldsensorData = newSensorData;
                }
    
                throw new NotImplementedException();            
            }
    
            private SensorData ReadSensorData()
            {
                SensorData newSensorData = new SensorData();
                //Code block to read sensor data from external device and save it to "newSensorData" object
    
                return newSensorData;
            }
        }
    

    我的客户端视图如下所示: 1. LineData.cshtml

    @{
        ViewBag.Title = "Line Data";
    }
    
    <h1>Linie: @ViewBag.LineNr</h1>
    
    <h2>Temperature</h2>
    <div id="sensorData"></div>
    
    @section scripts{
        <script>
            var LineNr = parseInt(@ViewBag.LineNr);
        </script>
    
        <script src="~/signalr/js"></script>
        <script src="~/Scripts/my/SignalR.js"></script>
    }
    

    和 2. 我的 SignalR.js

    (function () {
    
        var myHub = $.connection.data;
    
        // start hub connection
        $.connection.hub.start()
            .done(function () {
                //Register line number for group name
                myHub.server.registerName(LineNr, $.connection.hub.id);
            })
            .fail(function () {
                alert("SignalR Error for Line " + LineNr + " !");
            });
    
    
        // try reconnect after 5s
        $.connection.hub.disconnected(function () {
            setTimeout(function () {
                $.connection.hub.start();
            }, 5000); // Restart connection after 5 seconds.
        });
    
        // Clients functions
        myHub.client.announceToLine = function (data) {
            $("#sensorData").html(data);
        }
    
    })()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-16
      • 2021-10-08
      • 1970-01-01
      相关资源
      最近更新 更多