在 MVC 控制器中打开 websocket 通道
Posted
技术标签:
【中文标题】在 MVC 控制器中打开 websocket 通道【英文标题】:Opening a websocket channel inside MVC controller 【发布时间】:2016-02-22 12:48:00 【问题描述】:有没有人在 MVC 控制器中打开 websocket 连接有什么好的经验?
技术栈: ASPNET Core 1.0 (RC1) MVC、dnx46、System.Net.WebSockets
为什么使用 MVC 而不是中间件:为了整体一致性、路由、已注入的存储库、在同一控制器中调用私有方法的选项。
[HttpGet("v1/resources/id")]
public async Task<IActionResult> GetAsync(string id)
var resource = await this.repository.GetAsync(id);
if (resource == null)
return new HttpStatusCodeResult(404);
if (this.HttpContext.WebSockets.IsWebSocketRequest)
var webSocket = await this.HttpContext.WebSockets.AcceptWebSocketAsync();
if (webSocket != null && webSocket.State == WebSocketState.Open)
while (true)
var response = string.Format("Hello! Time 0", System.DateTime.Now.ToString());
var bytes = System.Text.Encoding.UTF8.GetBytes(response);
await webSocket.SendAsync(new System.ArraySegment<byte>(bytes),
WebSocketMessageType.Text, true, CancellationToken.None);
await Task.Delay(2000);
return new HttpStatusCodeResult(101);
问题:在中间件中处理 websocket 连接是否有任何已知的缺点?握手呢,除了返回 HTTP 101 状态码,我们还需要做什么吗?
更新 1:为什么不使用 SignalR? 不需要使用后备技术,因此虽然它是一款不错的产品,但在这种情况下添加额外的依赖项并没有什么好处。
更新 2: 我已经注意到一个缺点 - 当 while(true) 存在时(为了简单起见,上面的示例中没有显示,比如说,当频道需要关闭),方法需要返回一些东西(任务)。它应该是什么? HTTP 200 状态响应?我猜不是,因为在 WebSockets 文档中写到,在“关闭”帧之后什么都不应该发送。
更新 3: 我学到了一件事,那就是如果你想在 Windows 10 上使用 IIS Express 10.0 在 Visual Studio 2015 中调试时让 WebSockets 工作,你仍然必须使用 @987654321 @ 并在 Startup.cs 文件中配置 app.UseWebSockets()。否则,IsWebSocketRequest 将为 false。有谁知道为什么?握手?
【问题讨论】:
使用 SignalR asp.net/signalr 我已经成功地将 websocketsharp 与 MVC6 / MVC Core 1.0 / 本周他们称之为的任何东西混合在一起。事情不通过 OWIN 中间件管道,但您可以在不同的端口上运行 Web 套接字服务器并让它为 WS 连接提供服务。只是思考的食物。 未验证,但我怀疑“最正确”的方法是定义您自己的IActionResult
自定义实现,并在其 ExecuteResultAsync
方法中使用 websocket 循环。然后控制器只返回一个实例。
我只是这样做了——我将 websocket 处理循环放在自定义 IActionResult 类的 ExecuteResultAsync 中。这避免了其他中间件尝试在 OnStartup 中设置内容但已发送标头的问题。
能否请您与我们分享您的最终实现,了解您是如何在 asp.net MVC 5 的操作方法中运行 WebSocket 的?
【参考方案1】:
看起来不错。
您可能希望将while(true)
更改为while (!HttpContext.RequestAborted.IsCancellationRequested)
,以便检测客户端断开连接并结束请求。
调用accept 后无需检查null 或websocket 的状态。
我假设所有这些代码都是临时的,您实际上会从 websocket 读取一些内容。
所有常用的 websocket 规则都适用:
使用 SSL(当您实际托管时) 它不适用于多台服务器(它是点对点套接字连接) 您需要支持处理部分帧。如果您知道客户不会发送任何内容,则可以取消此操作。【讨论】:
谢谢,很棒的提示!我不会从服务器端的套接字读取数据。以上是关于在 MVC 控制器中打开 websocket 通道的主要内容,如果未能解决你的问题,请参考以下文章