我对SignalR很陌生。我在React中设置了一个前端,该前端连接到SignalR后端,该后端本身通过OPC-UA连接到机器[[(这是一个学校项目)
该程序的目的是将实时数据从PLC传输到我的React前端
。我现在的操作方式是:通过前端中的按钮进行连接->前端会调用一种方法,该方法订阅一些PLC节点,然后将数据发送回去。[我的问题是,我需要保持被调用的方法以'while(true)'循环运行,否则会因为设置了Hub对象而发生错误。
((当节点值更改时,这会使PLC调用SubscriptionHandler,这将导致错误,因为Hub对象不再存在我认为
)->(new OpcSubscribeDataChange("ns=6;s=::Program:Cube.Command.CntrlCmd", SubscriptionHandler)
如何在不处理集线器对象的情况下以适当的方式保持连接的活动?
这是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
}
}
集线器对象生存期您不实例化Hub类或从服务器上自己的代码调用其方法; SignalR Hubs管道为您完成了所有这些工作。每次需要处理Hub操作(例如,当客户端连接,断开连接或对服务器进行方法调用时)时,SignalR都会为您的Hub类创建一个新实例。
因为Hub类的实例是瞬态的,所以您不能使用它们来维护从一个方法调用到下一个方法调用的状态。每次服务器从客户端收到方法调用时,您的Hub类的新实例都会处理该消息。要通过多个连接和方法调用维护状态,请使用其他一些方法,例如数据库,Hub类上的静态变量,或者不是从Hub派生的其他类。如果使用Hub类上的静态变量之类的方法将数据保留在内存中,则当应用程序域回收时,数据将丢失。
您需要编写一个类,其中具有OPC客户端和OPC订阅作为成员。该类应通过DependencyInjection插入到集线器中,例如,请参见示例[Dependency Injection in SignalR]中的[[IStockTicker