SignalR恒定的数据流?

时间:2020-03-17 17:58:03

标签: c# stream signalr opc-ua

我对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
        }
    }

1 个答案:

答案 0 :(得分:0)

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

集线器对象寿命

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

因为Hub类的实例是瞬态的,所以您不能使用它们来维护从一个方法调用到下一个方法调用的状态。每次服务器从客户端收到方法调用时,您的Hub类的新实例都会处理该消息。要通过多个连接和方法调用维护状态,请使用其他一些方法,例如数据库,Hub类上的静态变量,或者不是从Hub派生的其他类。如果您使用Hub类上的静态变量之类的方法将数据保留在内存中,则当应用程序域回收时,数据将丢失。

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

中的 IStockTicker 示例
相关问题