ASP.NET 核心 SignalR 将服务添加到集线器中断

ASP.NET Core SignalR Adding service to hub breaks

我目前正在开发 ASP.NET 核心 Web 应用程序。

我有一个 MQTT 服务器,它连接到一个服务 (IHostedService),这个服务引用了一个 SignalR Hub。 因此,如果有来自 MQTT 服务器的新消息,它会转发到集线器,从而转发到客户端。

这很好用。但是现在我想添加一个按钮来将 MQTT 消息发送回 MQTT 服务器。

为此,我在集线器中添加了一个函数,该函数由按钮通过 SignalR 调用。

到目前为止一切顺利,但是当我现在将服务添加到集线器的构造函数时它失败了,当我打开网络应用程序时(不是在启动期间),并显示以下消息:

fail: Microsoft.AspNetCore.SignalR.HubConnectionHandler[1]
      Error when dispatching 'OnConnectedAsync' on hub.
System.InvalidOperationException: Unable to resolve service for type 'websiteApp.HostedServices.UserPromptService' while attempting to activate 'websiteApp.Hubs.UserPromptHub'.
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
   at lambda_method(Closure , IServiceProvider , Object[] )
   at Microsoft.AspNetCore.SignalR.Internal.DefaultHubActivator'1.Create()
   at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher'1.OnConnectedAsync(HubConnectionContext connection)
   at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher'1.OnConnectedAsync(HubConnectionContext connection)
   at Microsoft.AspNetCore.SignalR.HubConnectionHandler'1.RunHubAsync(HubConnectionContext connection) 

服务声明如下所示:

public class UserPromptService : IHostedService, IDisposable
{

    public UserPromptService(ILogger<UserPromptService> logger, IConfiguration config, UserPromptContext userPromptContext, IHubContext<UserPromptHub> userPromptHub)
    {

    }
}

我的集线器看起来像这样:

public class UserPromptHub : Hub<IUserPromptHub>
{
    public UserPromptHub(UserPromptService service) // everything works until I add the service here
    {
        service.ToString(); // just for testing
    }
}

并且它们配置在Startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapHub<Hubs.UserPromptHub>("/userPromptHub");
    });
}

以及在Program.cs中:

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                // ...
                .ConfigureServices(services =>
                {
                    services.AddSingleton<websiteApp.DataContext.UserPromptContext>();
                    services.AddHostedService<HostedServices.UserPromptService>();
                });

你能帮我解决这个问题吗?

解决您的问题的一个选择是稍微重组您的代码 bit.So 而不是您的 UserPromptService 负责 MQTT 连接,您为此创建一个单独的 class。

以下只是sudo代码

您可以创建一个新的 class

public class MQTTConnection
{
    private readonly _yourMQTTServerConnection;
    
    public MQTTConnection()
    {
        _yourMQTTServerConnection = new ServerConnection(connectionstring etc);
    }

    public Task<Message> GetMessage()
    {
       return _yourMQTTServerConnection.GetMessageAsync();
    }

    public Task SendMessage(Message message)
    {
        return _yourMQTTServerConnection.SendMessageAsync(message);
    }
}

所以你的集线器看起来像这样

public class UserPromptHub : Hub<IUserPromptHub>
{
    private readonly MQTTConnection _connection;        

    public UserPromptHub(MQTTConnection connection) 
    {
        _connection = connection
    }

    public async Task MessageYouReceiveFromTheUser(object object)
    {
        // your business logic 
       await _connection.SendMessage(message);
    }

    public Task MessageYouSendToTheClient(object object)
    {
        await Clients.All.MessageYouSendToTheClient(message);
    }
}

你的 UserPromptService 看起来有点像那样

public class UserPromptService : IHostedService, IDisposable
{

    public UserPromptService(ILogger<UserPromptService> logger, 
                             IConfiguration config, 
                             UserPromptContext userPromptContext, 
                             IHubContext<UserPromptHub> userPromptHub,
                             MQTTConnection connection)
    {
        // map arguments to private fields
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
       while(yourAppIsUpAndRunning)
       {
          var message = await _connection.GetMessage()
          // process the message
          await _hub.MessageYouSendToTheClient(yourMessage)
       }
    }
}

我希望我的方法是可以理解的,如果不是我可以添加更多细节。