从 "other place in code" 中获取 SignalR Hub 而不会丢失其客户端

Obtaining SignalR Hub without losing its clients from "other place in code"

我有一个应用程序,该应用程序必须通过 USB 端口连接的外部设备在网页上显示数据

之前,我给了用户按钮 "Start listening",它向后端发送 http 请求,后端开始监听端口(并阻止了应用程序,但没问题,因为它应该同时由 1 个人使用)直到收到无错误响应 (SerialDataReceivedEvent/SerialErrorReceivedEvent) SerialData 从该请求返回并显示在页面

我必须使用 SignalR 重写它,所以我很快就想出了这样一个天真的解决方案:

public class DeviceReaderHub : Hub
{
    private readonly IConfiguration _config;
    // this is static because listening that port (SerialPort) has to stay open
    private static DeviceReader_Helper _service;

    public DeviceReaderHub(IConfiguration config)
    {
        _config = config;

        if (_service == null)
        {
            _service = new DeviceReader_Helper();
            _service.Open(_config["DeviceInfo:Port"]);
        }

        _service.DataReceived_Delegate = SendMessage;
        _service.ErrorReceived_Delegate = SendErrorMessage;
    }

    public async Task SendMessage(string message)
    {
        await Clients.All.SendAsync("onRead", message);
    }

    public async Task SendErrorMessage(string message)
    {
        await Clients.All.SendAsync("onRead", $"error = {message}");
    }

    public async override Task OnConnectedAsync()
    {
        await Clients.All.SendAsync("onConnected");
        await base.OnConnectedAsync();
    }
}

但我很快就收到了现实检查 - 我不能那样做,因为 DeviceReaderHub 被处理了。

Exception thrown: 'System.ObjectDisposedException' in Microsoft.AspNetCore.SignalR.Core.dll

我考虑在 SerialDataReceivedEventSerialErrorReceivedEvent 被调用时获取新的 DeviceReaderHub 中心 但我不知道如何在不丢失连接的客户端的情况下获取集线器实例

SignalR 集线器是瞬态对象,这意味着新的集线器实例用于来自客户端的集线器上的每个方法调用。根据this Microsoft Docs:

Don't store state in a property on the hub class. Every hub method call is executed on a new hub instance.

因此,除了接收和处理来自客户端的请求外,您不应使用集线器执行任何其他操作。为了将消息发送到集线器外部的客户端,SignalR 提供了 HubContext<T> class,可从依赖注入中获得。例如:

public class DeviceReader_Helper {

    private readonly IHubContext<DeviceReaderHub> _hubContext;

    // you can obtain hubContext either from constructor DI, or service locator pattern with an IServiceProvider
    public DeviceReader_Helper(IHubContext<DeviceReaderHub> hubContext) {
        _hubContext = hubContext;
    }

    public async Task SendMessage(string message) {
        await _hubContext.Clients.All.SendAsync("onRead", message);
    }
}

有关详细信息,请参阅 this。至于你担心的

but I have not idea how can I get instance of the hub without losing connected clients

无需集线器实例即可连接客户端。集线器仅用于接收来自客户端的消息,并不是保持客户端与服务器连接所必需的。