如何获取ASP.NET Core中所有SignalR Core Hub及其映射路由URL?
ASP.NET Core 中获取所有SignalR Hub及对应路由的实现方式
SignalR Hub的路由注册信息不会被收录到IActionDescriptorCollectionProvider的集合中,因为Hub不属于MVC Action的端点体系,无法通过Action相关的服务拿到全量清单。需要依托ASP.NET Core内置的终结点路由(Endpoint Routing)的数据源实现遍历提取,最终生成Dictionary<Type, string>形式的Hub类型到路由路径的映射。
核心实现逻辑
- 从DI容器中获取所有注册的
IEndpointDataSource实例:框架会把所有映射的端点(包括MVC Controller、Razor Pages、SignalR Hub、健康检查等)按来源拆分到不同的端点数据源中,枚举所有数据源即可覆盖全量注册的端点 - 遍历每个数据源中的端点集合,筛选出携带
HubMetadata元数据的端点:所有通过MapHub<THub>()方法映射的SignalR端点,都会自动附带该元数据,元数据内直接存储了对应Hub的Type类型 - 对筛选出的Hub端点,从其关联的
RouteEndpoint中提取原始路由模板字符串,整理为要求的键值对结构
可直接复用的实现代码
在Program.cs中完成常规的SignalR注册和Hub映射后,执行枚举逻辑即可生成目标字典:
var builder = WebApplication.CreateBuilder(args); // 常规SignalR服务注册 builder.Services.AddSignalR(); var app = builder.Build(); // 常规Hub路由映射 app.MapHub<ChatHub>("/chathub"); app.MapHub<NotificationHub>("/notificationHub"); // 初始化Hub和路由的映射字典 var endpointDataSources = app.Services.GetRequiredService<IEnumerable<EndpointDataSource>>(); var hubPathDict = new Dictionary<Type, string>(); foreach (var dataSource in endpointDataSources) { foreach (var endpoint in dataSource.Endpoints) { // 匹配带Hub元数据的端点 var hubMetadata = endpoint.Metadata.GetMetadata<HubMetadata>(); if (hubMetadata == null) continue; if (endpoint is RouteEndpoint routeEndpoint) { // 提取原始路由模板,如"/chathub" var routePath = routeEndpoint.RoutePattern.RawText; hubPathDict[hubMetadata.HubType] = routePath; } } }
注意事项
- 枚举端点的操作必须在所有
Map*路由方法执行完成后执行,不能在服务注册阶段(ConfigureServices/builder.Services阶段)获取,否则会因为端点尚未完成注册拿到空集合 - 该方式提取到的路由值是路由模板的原始字符串,如果Hub路由配置了参数(如
/tenant/{tenantId}/hub),拿到的值会是带占位符的模板,而非运行时的实际请求路径 - 如果需要在应用的其他组件中复用这个映射关系,可以将上述枚举逻辑封装为单例服务,应用启动完成后完成字典初始化,后续通过DI注入直接使用,无需重复遍历端点集合
- 该实现适用于ASP.NET Core 3.0及以上使用终结点路由(即
app.MapHub方式注册Hub)的场景,对于2.x版本使用app.UseSignalR的传统路由模式,需要通过反射遍历已注册的Hub路由信息实现,兼容性较差不推荐
内容的提问来源于stack exchange,提问作者alireza.salemian
相关产品推荐
相关产品推荐

