我完全按照 MS 规则定义我的强类型 SignalR 集线器
public class OutputMessages : Hub<IOutputMessages>
{...}
用同样的方式将我的 SignalR hub 注入控制器
public class ApplicationAPIController : ControllerBase
{
public ApplicationAPIController(IHubContext<OutputMessages, IOutputMessages> _outputMessages)
{...}
}
在启动中我将 SignalR 服务添加为
services.AddSignalR()
.AddHubOptions<OutputMessages>(options =>
{
options.EnableDetailedErrors = true;
})
并定义端点
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<OutputMessages>("/OutputMessages", options =>
{
options.Transports =
HttpTransportType.WebSockets |
HttpTransportType.LongPolling;
});
});
看起来不错吗?是的。而且编译也不错。但在运行时我收到
fail: Microsoft.AspNetCore.SignalR.HubConnectionHandler[1]
Error when dispatching 'OnConnectedAsync' on hub.
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.SignalR.Hub`1[IOutputMessages]' while attempting to activate 'OutputMessages'.
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)
dbug: Microsoft.AspNetCore.SignalR.HubConnectionHandler[6]
OnConnectedAsync ending.
最后我找到了解决方案
这是我的强类型集线器定义
public class OutputMessages : Hub<IOutputMessages>
{
public static readonly Dictionary<string, string> ConnectedUserList = new Dictionary<string, string>(1024);
private readonly IHubContext<OutputMessages,IOutputMessages> _hubContext;
private readonly ApplicationDbContext _db;
private readonly ILogger<OutputMessages> _logger;
public OutputMessages(IHubContext<OutputMessages, IOutputMessages> hubContext, ILogger<OutputMessages> logger, ApplicationDbContext dbContext)
{
_hubContext = hubContext;
_db = dbContext;
_logger = logger;
}
....
public async Task AdminMessages2(string userId, string message, bool consoleOnly)
{
string uname = await Username(userId);
await _hubContext.Clients.All.AdminMessages2(userId, "API: " + uname + " " + message, consoleOnly);
}
[ResponseCache(VaryByHeader = "id", Duration = 36000, Location = ResponseCacheLocation.Any)]
public async Task<string> Username(string id)
{
ApplicationUser user = null;
await Task.Run(() => user = _db.Users.Find(id));
return user.UserName;
}
public override async Task OnConnectedAsync()
{
string JWT = Context.GetHttpContext().Request.Headers["Authorization"];
string ValidUserID = UserHelpers.ValidateJWT(JWT);
if (ValidUserID != null)
{
_logger.LogInformation($"User {ValidUserID} connected to {this.GetType().Name} hub");
if (ConnectedUserList.Any(x => x.Key == ValidUserID))
{
ConnectedUserList.Remove(ValidUserID);
}
ConnectedUserList.Add(ValidUserID, Context.ConnectionId);
}
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(System.Exception exception)
{
var JWT = Context.GetHttpContext().Request.Headers["Authorization"];
string ValidUserID = UserHelpers.ValidateJWT(JWT);
if (ValidUserID != null)
{
_logger.LogInformation($"User {ValidUserID} disconnected from {this.GetType().Name} hub");
if (ConnectedUserList.Any(x => x.Key == ValidUserID))
{
ConnectedUserList.Remove(ValidUserID);
}
ConnectedUserList.Add(ValidUserID, Context.ConnectionId);
}
await base.OnDisconnectedAsync(exception);
}
}
这是控制器的注入集线器
public class ApplicationAPIController : ControllerBase
{
public ApplicationAPIController(ILogger<ApplicationAPIController> logger, ApplicationDbContext dbContext, IConfiguration Configuration, CoreObjectDumper.CoreObjectDumper dump, IHubContext<OutputMessages, IOutputMessages> _outputMessages)
{
...
StartUp 中 SignalR 服务的定义没有改变。问题是从类而不是接口创建 Hub,并且 Hub 构造函数必须完全是 IHubContext
就我而言,发生此错误时我正在使用 ABP 框架,我发现 ABP(部分)删除了缺少 DI、IOnlineClientManager 的类的实现
解决方案是删除这些类的通用实现(以及它们被引用的任何地方)
IOnlineClientManager<ChatChannel> onlineClientManager,
在这里删除
ChatChannel
为我解决了这个问题。
当我在代码中使用 SignalR 时,我遇到了同样的问题。除集线器连接外,所有其他 REST 端点均按预期工作。启用下面的代码后,我能够在 Visual Studio 输出窗格中看到错误:
services.AddSignalR()
.AddHubOptions<OutputMessages>(options =>
{
options.EnableDetailedErrors = true;
})
我传递给集线器中的构造函数的某些类的依赖注入存在问题。一旦我解决了 DI 问题,集线器连接就按预期工作了。