如何在Swagger中接收SignalR Hub消息?(.NET 6 Web API场景)
在Swagger中接收SignalR响应的实现方案
问题背景
基于.NET 6.0开发的Web API集成了SignalR,使用SignalRSwaggerGen包可在Swagger中发送SignalR请求,但无法接收Socket响应,该包开发者明确表示不支持此功能,现需实现Swagger内接收SignalR响应的功能。
现有代码
ConfigureServices 配置
public void ConfigureServices(IServiceCollection services) { services.AddSignalR(options => { options.EnableDetailedErrors = true; }); services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Game", Version = "v1" }); c.AddSignalRSwaggerGen(ssgOption => ssgOption.HubPathFunc = (hubPath) => "/game"); }); }
端点配置
app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapHub<GameHub>("/game", config => { config.Transports = HttpTransportType.WebSockets; }); }); app.Run(async (context) => { var hubConnection = new HubConnectionBuilder().WithUrl($"https://{context.Request.Host.Value}/game{context.Request.QueryString}").WithAutomaticReconnect().Build(); await hubConnection.StartAsync(); });
实现方法
由于原生Swagger和SignalRSwaggerGen均不支持WebSocket响应接收,最可靠的方式是自定义Swagger UI扩展,嵌入SignalR客户端逻辑来接收消息。
步骤1:自定义Swagger UI的Index页面
修改Program.cs中的SwaggerUI配置,指定使用自定义的index.html文件:
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Game v1"); // 替换成你的项目命名空间和资源路径 c.IndexStream = () => typeof(Program).Assembly.GetManifestResourceStream("GameAPI.Swagger.index.html"); });
步骤2:创建自定义index.html
在项目中新建Swagger文件夹,添加index.html文件,设置其生成操作为嵌入的资源。文件内容如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Game API Swagger UI</title> <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.15.5/swagger-ui.css" /> <style> #signalr-panel { margin: 20px 0; padding: 15px; border: 1px solid #d9d9d9; border-radius: 4px; } #signalr-messages { height: 250px; overflow-y: auto; margin-top: 10px; padding: 10px; background-color: #fafafa; border-radius: 4px; } .message-line { margin-bottom: 8px; padding: 6px; background-color: #fff; border-radius: 2px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); } .message-time { color: #666; font-size: 12px; margin-right: 8px; } </style> </head> <body> <div id="swagger-ui"></div> <div id="signalr-panel"> <h3>SignalR 消息接收区</h3> <button onclick="connectToHub()">连接SignalR Hub</button> <button onclick="clearMessages()">清空消息</button> <div id="signalr-messages"></div> </div> <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.15.5/swagger-ui-bundle.js"></script> <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.15.5/swagger-ui-standalone-preset.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.21/signalr.min.js"></script> <script> window.onload = function() { const ui = SwaggerUIBundle({ url: "/swagger/v1/swagger.json", dom_id: '#swagger-ui', presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], layout: "StandaloneLayout" }); window.ui = ui; }; let hubConnection; function connectToHub() { if (hubConnection && hubConnection.state === signalR.HubConnectionState.Connected) { alert("已处于连接状态"); return; } hubConnection = new signalR.HubConnectionBuilder() .withUrl("/game") .withAutomaticReconnect() .build(); // 监听服务端推送的所有方法,替换成你的Hub中实际定义的客户端方法 hubConnection.on("ReceiveGameUpdate", (updateContent) => { addMessage(`游戏更新: ${JSON.stringify(updateContent)}`); }); hubConnection.on("PlayerJoined", (playerName) => { addMessage(`玩家加入: ${playerName}`); }); hubConnection.start() .then(() => addMessage("SignalR Hub 连接成功")) .catch(err => addMessage(`连接失败: ${err.message}`)); } function addMessage(content) { const messagesDiv = document.getElementById("signalr-messages"); const messageElement = document.createElement("div"); messageElement.className = "message-line"; messageElement.innerHTML = `<span class="message-time">${new Date().toLocaleString()}</span>${content}`; messagesDiv.appendChild(messageElement); messagesDiv.scrollTop = messagesDiv.scrollHeight; } function clearMessages() { document.getElementById("signalr-messages").innerHTML = ""; } </script> </body> </html>
步骤3:适配你的SignalR Hub方法
在上述html的JavaScript代码中,将hubConnection.on中的方法名(如ReceiveGameUpdate、PlayerJoined)替换为你的GameHub中实际定义的客户端接收方法。
注意事项
- 确保SignalR客户端版本与服务端.NET 6.0版本兼容(示例中使用6.0.21版本)
- 自定义index.html中的资源CDN链接可根据需要更新版本
- 如果你的API启用了身份验证,需要在SignalR连接中携带认证信息(如JWT token)
内容的提问来源于stack exchange,提问作者Gegham Hunanyan
相关产品推荐
相关产品推荐

