将 SignalR 注入核心 WorkerService

Injecting SignalR into a Core WorkerService

我正在尝试将 SignalR 注入到 WorkerService 项目中,然后模拟服务器端通知。

在我的 Worker.cs 文件中,我得到一些空引用 - 这告诉我最初我的 Hub 对象不正确。

我先用同名项目创建了一个NotificationHub solution

这是 Notifications.cs - 效果很好。

using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NotificationHub.Hubs
{
    public interface IHubClient
    {
        Task MessageReceived(string user, string message);
        Task MessageReceived(string message);
    }

    public class Notifications: Hub<IHubClient>
    {
        [HubMethodName("SendMessageToClient")]
        public async Task SendMessage(string username, string message)
        {
            await Clients.All.MessageReceived(username, "from Notification Hub:" + message);
        }
        
        public override Task OnConnectedAsync()
        {
            Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
            _ = SendMessage("From Server", "Hub reconnected on server.");
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            Console.Write("Hub just disconnected on server.");
            return base.OnDisconnectedAsync(exception);
        }
    }
}

NotificationHub 在我本地机器上的 IIS 中运行,让我从我的 TypeScript 客户端调用通知中心。

即我只是添加了一个简单的 HTML button 来触发来自客户端的消息。我的函数触发:

   this.hubConnection.send('SendMessageToClient', 'client', `Message from client side. ${today}`)
                    .then(() => console.log('Message sent from client.'));

Core WorkerService:我的问题就在这里

然后我添加了一个 NotificationWorkService,我试图在其中注入 SignalR。目标是最终在 Windows 服务器上提供此服务 运行,该服务器会定期检查通知,并将它们传送到浏览器。

在我的 WorkerService 项目中,这里是 Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace HarmonyNotificationWorkerService
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }
}

这里是 Worker.cs -

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NotificationHub.Hubs;

namespace HarmonyNotificationWorkerService
{
    public interface IHubClient
    {
        Task MessageReceived(string user, string message);
        Task MessageReceived(string message);
    }

    public class Worker : BackgroundService
    {
        private IHubContext<Notifications> _hubContext;
        private readonly Hub<IHubClient> _hubNotif;
        private readonly ILogger<Worker> _logger;
       
        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            using (var hubConnection = new HubConnection("/hub"))
            {
                IHubProxy hubproxy = hubConnection.CreateHubProxy("https://localhost:44311/hub");

                await hubproxy.Invoke("SendMessage", "test");
            }
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
              
                await Task.Delay(1000, stoppingToken);
            }
        }

        private async Task CheckForNotifications()
        {                      
            await _hubNotif.Clients.All.MessageReceived("from work server", "Dude, you've got mail!");
        }
    }
}

问题:

问题是 _hubContext_hubNotif 对象总是空的,所以我无法测试其中任何一个。我最初没有正确定义它们,但我不确定该怎么做。 C# 还向我显示有关此空引用的警告。

System.InvalidOperationException: 'Data cannot be sent because the connection is in the disconnected state. Call start before sending any data.`

更新 - 安装 SIGNALR 客户端程序包

我在Worker.cs中添加了using Microsoft.AspNetCore.SignalR.Client;,并在Workerclass的顶部设置了一个 private readonly HubConnection _hubConnection;

然后我修改了下面的方法来检查conn状态,然后发送消息:

 private async Task CheckForNotifications()
        {
            if (_hubConnection.State == HubConnectionState.Disconnected)
            {
                await _hubConnection.StartAsync();
            }            
            _ = _hubConnection.SendAsync("SendMessageToClient", "from service worker", "You've got mail!");
        }

一切似乎都很顺利。

线程有时会以 code 0 退出,但我相信在这种情况下这是正常的,因为我在 Task.Delay(5000);

上 运行

不要混合使用 ASP.NET SignalR 和 ASP.NET Core SignalR。它们彼此不相容。您的服务器正在使用 ASP.NET Core SignalR,因此您的工作人员应该使用 HubConnectionBuilder.

创建一个 HubConnection

https://docs.microsoft.com/aspnet/core/signalr/dotnet-client?view=aspnetcore-3.1&tabs=visual-studio#connect-to-a-hub.