ASP.NET中API控制器HttpGet方法无法使用WebSocket发送数据如何解决
问题根因
你遇到的异常本质是WebSocket连接存续期间,对应的Http请求上下文被提前释放了,具体原因有两个:
- 控制器Action使用了
async void返回值:ASP.NET Core控制器的异步Action如果返回void,框架不会等待完整异步逻辑执行完成,只要方法执行到第一个await点,就会直接标记请求处理完成,释放HttpContext和响应流,后续WebSocket的收发操作自然会触发ObjectDisposedException。 - 中间件执行逻辑的差异:你写在中间件里正常是因为自定义中间件通常返回
Task,ASP.NET Core会等待中间件的Task完全执行完成后才会结束请求管道,符合WebSocket需要长期持有管道的要求。
解决方案
按以下步骤修改即可:
- 将控制器Action的返回值从
async void改为async Task:ASP.NET Core会等待整个Task执行完成后再释放请求上下文,保证WebSocket连接存续期间资源可用。 - 确保Program.cs/Startup.cs中
app.UseWebSockets()的注册顺序在控制器中间件之前,避免WebSocket握手前请求被控制器预处理异常。 - 可选优化:使用
HttpContext.RequestAborted作为WebSocket操作的取消令牌,客户端主动断开时可以及时终止后台循环,避免资源泄漏。
修正后代码示例
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; namespace Null.SimpleFishing.Controllers.WS { [Route("api/[controller]")] [ApiController] public class WSController : ControllerBase { // 核心修改:返回值从async void改为async Task [HttpGet] public async Task Get() { if (HttpContext.WebSockets.IsWebSocketRequest) { using (WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync()) { await Echo(webSocket, HttpContext.RequestAborted); } } else { Response.StatusCode = StatusCodes.Status400BadRequest; } } private async Task Echo(WebSocket webSocket, CancellationToken cancellationToken) { var buffer = new byte[1024 * 4]; WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken); while (!result.CloseStatus.HasValue) { await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, cancellationToken); result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken); } await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, cancellationToken); } } }
前端代码不需要修改,直接使用即可正常运行。
内容的提问来源于stack exchange,提问作者SlimeNull
相关产品推荐
相关产品推荐

