You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET中API控制器HttpGet方法无法使用WebSocket发送数据如何解决

问题根因

你遇到的异常本质是WebSocket连接存续期间,对应的Http请求上下文被提前释放了,具体原因有两个:

  1. 控制器Action使用了async void返回值:ASP.NET Core控制器的异步Action如果返回void,框架不会等待完整异步逻辑执行完成,只要方法执行到第一个await点,就会直接标记请求处理完成,释放HttpContext和响应流,后续WebSocket的收发操作自然会触发ObjectDisposedException。
  2. 中间件执行逻辑的差异:你写在中间件里正常是因为自定义中间件通常返回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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 11:54:02