.NET Core 6注入SignalR Hub到控制器报INotificationHub服务解析错误
问题原因
AddSignalR()方法默认仅注册SignalR运行核心依赖、IHubContext<THub>类型的Hub上下文服务,不会自动将自定义的Hub类、自定义的INotificationHub接口加入依赖注入容器,容器找不到对应服务注册项就会抛出激活失败的异常。- SignalR Hub本身是短生命周期对象,仅在客户端建立连接、发起Hub方法调用时由框架临时实例化,请求处理完成后立即释放,本身就不支持直接作为服务注入到控制器等其他组件中,直接注入Hub实例不符合框架设计规范,即使手动注册也会因为缺失连接上下文导致运行时错误。
正确配置方法
根据你的使用场景选对应方案即可:
方案1:直接注入Hub上下文(官方推荐,无需额外抽象)
如果只是需要在控制器中向SignalR连接的客户端推送消息,不需要额外抽象接口,直接注入IHubContext<NotificationHub>即可,该对象包含全部客户端消息推送的API,和直接在Hub类中操作的体验完全一致。
- 修改控制器构造函数,替换原有的
INotificationHub注入参数:
<ApiController> <Route("[controller]/[action]")> Public Class NotificationController Inherits ControllerBase ' 定义私有字段存储Hub上下文 Private ReadOnly _hubContext As IHubContext(Of NotificationHub) Sub New(ByVal UserService As IUserService, Cryptor As IAesCryptor, DbContext As ApplicationDbContext, httpContextAccessor As IHttpContextAccessor, Logger As ILogger(Of NotificationController), Configuration As IConfiguration, NotificationService As INotificationCacheService, HubContext As IHubContext(Of NotificationHub)) ' 其他服务赋值逻辑省略 _hubContext = HubContext End Sub End Class
- 需要推送消息时,直接调用
_hubContext的API即可,例如给所有在线用户推送消息:
Await _hubContext.Clients.All.SendAsync("ReceiveNotification", "测试消息")
方案2:自定义接口抽象(适合需要解耦Hub逻辑的场景)
如果需要通过INotificationHub接口做解耦、统一管理消息推送逻辑,不要直接让Hub类实现该接口注册到DI,需要单独编写服务实现类包装IHubContext的逻辑:
- 定义推送接口:
Public Interface INotificationHub Task SendToUserAsync(String userId, Object notificationData) Task SendToAllAsync(Object notificationData) End Interface
- 编写接口实现类,内部依赖IHubContext完成推送:
Public Class NotificationHubService Implements INotificationHub Private ReadOnly _hubContext As IHubContext(Of NotificationHub) Public Sub New(hubContext As IHubContext(Of NotificationHub)) _hubContext = hubContext End Sub Public Async Function SendToUserAsync(userId As String, notificationData As Object) As Task Implements INotificationHub.SendToUserAsync Await _hubContext.Clients.User(userId).SendAsync("ReceiveNotification", notificationData) End Function Public Async Function SendToAllAsync(notificationData As Object) As Task Implements INotificationHub.SendToAllAsync Await _hubContext.Clients.All.SendAsync("ReceiveNotification", notificationData) End Function End Class
- 在服务注册代码中手动注册该抽象服务:
' 放在AddSignalR相关代码之后即可 Services.AddScoped(Of INotificationHub, NotificationHubService)
注册完成后就可以正常在控制器构造函数中注入INotificationHub使用了。
注意:不要尝试直接将
NotificationHub类本身注册为服务注入,手动从DI解析的Hub实例没有有效客户端连接上下文,调用Clients、Groups、Context等成员时会抛出空引用异常。
内容的提问来源于stack exchange,提问作者user18928007
相关产品推荐
相关产品推荐

