SignalR постоянный поток данных? - PullRequest
0 голосов
/ 17 марта 2020

Я совсем новичок в SignalR. Я установил интерфейс в React, который подключается к бэкэнду SignalR, который сам подключается к машине через OP C -UA (это школьный проект)

Цель программы для потоковой передачи данных с PL C на мой интерфейс React . Теперь я делаю это так: подключиться через кнопку в frontend -> Frontend вызывает метод, который подписывается на некоторые узлы PL C, который затем отправляет данные обратно.

Моя проблема в том, что мне нужно, чтобы вызываемый метод работал с 'while (true)' l oop, в противном случае я получаю сообщение об ошибке, поскольку объект Hub удаляется.

(Это заставляет PL C вызывать 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
        }
    }

1 Ответ

0 голосов
/ 03 апреля 2020

Согласно SignalR-Handbook , это предполагаемое поведение:

Время жизни объекта-концентратора

Вы не создаете экземпляр класса Hub или не вызываете его методы из вашего собственного кода на сервере; все, что делается для вас с помощью конвейера SignalR Hubs. SignalR создает новый экземпляр вашего класса Hub каждый раз, когда ему необходимо обработать операцию Hub, например, когда клиент подключается, отключается или выполняет вызов метода к серверу.

Поскольку экземпляры класса Hub являются временными их нельзя использовать для поддержания состояния от одного вызова метода к другому. Каждый раз, когда сервер получает вызов метода от клиента, новый экземпляр вашего класса Hub обрабатывает сообщение. Чтобы поддерживать состояние с помощью нескольких соединений и вызовов методов, используйте какой-либо другой метод, например базу данных, или переменную stati c в классе Hub, или другой класс, который не является производным от Hub. Если вы сохраните данные в памяти, используя метод, такой как переменная stati c, в классе Hub, данные будут потеряны при перезагрузке домена приложения.

Вам нужно написать класс, которые имеют подписки OP C Client и OP C в качестве участников. Класс должен быть вставлен в концентратор через DependencyInjection, см., Например, IStockTicker в Внедрение зависимостей в SignalR

...