【问题标题】:SignalR constant stream of data?SignalR 恒定的数据流?
【发布时间】:2020-04-03 23:20:37
【问题描述】:

我对 SignalR 很陌生。我在 React 中设置了一个前端,该前端连接到 SignalR 后端,该后端本身通过 OPC-UA 连接到机器 (这是一个学校项目)

该程序的目的是将实时数据从 PLC 流式传输到我的 React 前端。我现在这样做的方法是:通过前端中的按钮连接 -> 前端调用一个订阅一些 PLC 节点的方法,然后将数据发回。

我的问题是我需要让被调用的方法使用 'while(true)' 循环运行 否则我会收到错误,因为 Hub 对象已被释放。

(这会使 PLC 在节点值更改时调用 SubscriptionHandler,这会导致错误导致 Hub 对象不再存在 我认为)-> (new OpcSubscribeDataChange("ns=6;s=::Program:Cube.Command.CntrlCmd", SubscriptionHandler)

如何在不释放 Hub 对象的情况下以适当的方式保持连接?

这是 SignalR 代码:

using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
using System.Diagnostics;
using Opc.UaFx.Client;
using Connections;

namespace StreamBackend.Hubs
{
    public class DataHub : Hub
    {   
        private IHubContext<DataHub> _context;

        public override async Task OnConnectedAsync()
        {   
            await Groups.AddToGroupAsync(Context.ConnectionId, "ConnectedUsers");
            await base.OnConnectedAsync();
            Console.WriteLine("Client Connected");

            OPC.Client.Connect();

        }

        public override async Task OnDisconnectedAsync(Exception exception)
        {
            await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR");
            await base.OnDisconnectedAsync(exception);

            Console.WriteLine("Removed: " + Context.ConnectionId);
        }

        public DataHub(IHubContext<DataHub> context) {
            _context = context;

            // Implement check on whether connected already or not
            Console.WriteLine("Constructor");
        }

        public async void SubscriptionHandler(object sender, OpcDataChangeReceivedEventArgs e) {
            OpcMonitoredItem item = (OpcMonitoredItem)sender;
            var NodeId = Convert.ToString(item.NodeId);
            var Value = Convert.ToString(e.Item.Value);
            await SendData(NodeId, Value);
        } 

        public async Task SendData(string NodeId, string Value) {
            await Clients.All.SendAsync("LatestChange", NodeId, Value);
        }

        public async Task DataHubConnection()
        {
            await Clients.All.SendAsync("InvokeMethodFromBackend");

             OpcSubscribeDataChange[] nodes = new OpcSubscribeDataChange[] {
                    new OpcSubscribeDataChange("ns=6;s=::Program:Cube.Command.CntrlCmd", SubscriptionHandler),
                    new OpcSubscribeDataChange("ns=6;s=::Program:Cube.Command.Parameter[0].Value", SubscriptionHandler)
                };

                OpcSubscription subscription = OPC.Client.SubscribeNodes(nodes);

                // This keeps the "Hub" alive. It is needed, cause it is the SubscriptionHandlers accesspoint
                while(true) {
                    Console.WriteLine("Open");
                     System.Threading.Thread.Sleep(2000); //Hang out for half a second (testing)
                    }
                } 
                // 1006 error is when the server closes the connection
        }
    }

【问题讨论】:

  • 我会推荐 Webhooks 而不是信号 R。

标签: c# stream signalr opc-ua


【解决方案1】:

根据SignalR-Handbook,这是预期行为:

中心对象生命周期

您无需实例化 Hub 类或从您自己的服务器代码调用其方法; SignalR Hubs 管道为您完成的所有工作。 SignalR 每次需要处理 Hub 操作(例如客户端连接、断开连接或对服务器进行方法调用时)都会创建 Hub 类的新实例。

由于 Hub 类的实例是瞬态的,因此您不能使用它们来维护从一个方法调用到下一个方法调用的状态。每次服务器接收到来自客户端的方法调用时,您的 Hub 类的新实例都会处理该消息。要通过多个连接和方法调用来维护状态,请使用其他方法,例如数据库,或 Hub 类上的静态变量,或不是从 Hub 派生的不同类。如果你在内存中持久化数据,使用Hub类上的静态变量等方法,应用域回收时数据会丢失。

您需要编写一个类,该类具有 OPC 客户端和 OPC 订阅作为成员。该类应通过 DependencyInjection 插入到集线器中,参见 Dependency Injection in SignalR

中的示例 IStockTicker

【讨论】:

    猜你喜欢
    • 2019-06-26
    • 1970-01-01
    • 2020-02-09
    • 2012-09-02
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    相关资源
    最近更新 更多