如何在类中注入强类型信号集线器 [ASP CORE 2.2]

Ant*_*kov 4 signalr signalr-hub .net-core asp.net-core asp.net-core-signalr

我想在服务中注入我的强类型集线器,但我不喜欢 Microsoft 所示示例中的某些内容 - https://docs.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view =aspnetcore-2.2(注入强类型 HubContext)

public class ChatController : Controller
{
    public IHubContext<ChatHub, IChatClient> _strongChatHubContext { get; }

    public ChatController(IHubContext<ChatHub, IChatClient> chatHubContext)
    {
        _strongChatHubContext = chatHubContext;
    }

    public async Task SendMessage(string message)
    {
        await _strongChatHubContext.Clients.All.ReceiveMessage(message);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子ChatHub中耦合到ChatController.

所以我想注入用通用接口参数定义的集线器本身,并且不会在我的服务中定义它的具体实现。这是示例代码

public interface IReportProcessingClient
{
    Task SendReportInfo(ReportProgressModel report);
}
Run Code Online (Sandbox Code Playgroud)
public class ReportProcessingHub : Hub<IReportProcessingClient>
{
    public async Task SendMessage(ReportProgressModel report)
    {
        await Clients.All.SendReportInfo(report);
    }
}

Run Code Online (Sandbox Code Playgroud)
 public class ReportInfoHostedService : IHostedService, IDisposable
 {
     private readonly Hub<IReportProcessingClient> _hub;
     private readonly IReportGenerationProgressService _reportService;

     public ReportInfoHostedService(Hub<IReportProcessingClient> hub, IReportGenerationProgressService reportService)
     {
         _hub = hub;
         _reportService = reportService;
     }

     public Task StartAsync(CancellationToken cancellationToken)
     {
         _reportService.SubscribeForChange(async x =>
         {
             await _hub.Clients.All.SendReportInfo(x);
         });

         return Task.CompletedTask;
     }

     public Task StopAsync(CancellationToken cancellationToken)
     {
         return Task.CompletedTask;
     }

     public void Dispose()
     {
     }
 }
Run Code Online (Sandbox Code Playgroud)

这种方法显然需要在 Startup.cs 中额外注册集线器,因为它不是由 Microsoft 提供的上下文 api 调用的。

services.AddSingleton<Hub<IReportProcessingClient>, ReportProcessingHub>();
Run Code Online (Sandbox Code Playgroud)
app.UseSignalR(route => {
      route.MapHub<ReportProcessingHub>("/reportProcessingHub");
});
Run Code Online (Sandbox Code Playgroud)

一切都完成并工作,直到集线器尝试向客户端发送消息。然后我得到了例外

_hub.Clients.All threw an exception of System.NullReferenceException: 'Object reference not set to an instance of an object.'
Run Code Online (Sandbox Code Playgroud)

所以总结一下:

1. 这是注入强类型集线器的正确方法app.UseSingleR吗?我做错了什么(例如在服务中错误注册了集线器,错误使用了)?

2. 如果不是,正确的方法是什么?

注意:我知道有更简单的方法注入IHubContext<Hub<IReportProcessingClient>>,但这对我来说不是解决方案,因为我必须调用作为string参数传递的集线器方法名称。

itm*_*nus 5

我想......并且不会在我的服务中定义它的具体实现

  1. 如果您不想公开具体的集线器实现,则至少应该公开基类接口。但是,由于集线器应该从Hub类继承,因此我们不能在这里使用接口。因此,让我们创建一个公共基础集线器ReportProcessingHubBase以及一个内部混凝土ReportProcessingHub

    public abstract class ReportProcessingHubBase : Hub<IReportProcessingClient>
    {
        public abstract Task SendMessage(ReportProgressModel report);
    }
    
    // the concrete hub will NOT be exposed
    internal class ReportProcessingHub : ReportProcessingHubBase
    {
        public override async Task SendMessage(ReportProgressModel report)
        {
            await Clients.All.SendReportInfo(report);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 确保你已经注册了两个相关的服务:

    services.AddScoped<ReportProcessingHubBase, ReportProcessingHub>();
    services.AddHostedService<ReportInfoHostedService>();
    
    Run Code Online (Sandbox Code Playgroud)
  3. 确保您正在映射Base Hub最重要!):
     endpoints.MapHub<ReportProcessingHubBase>("/report");
    
    Run Code Online (Sandbox Code Playgroud)
  4. 最后,您可以通过注入来获取基本集线器IHubContext<ReportProcessingHubBase,IReportProcessingClient>

    public class ReportInfoHostedService : IHostedService, IDisposable
    {
        private readonly IHubContext<ReportProcessingHubBase,IReportProcessingClient> _hub;
    
        public ReportInfoHostedService(IHubContext<ReportProcessingHubBase,IReportProcessingClient> hub)
        {
            _hub = hub;
        }
    
        ...
     }
    
    Run Code Online (Sandbox Code Playgroud)

    现在,您可以以强类型方式调用 hub 方法。