当前位置: 首页 > 知识库问答 >
问题:

ASP.NET核心中间件项目中的“响应已经启动”异常

长孙沈义
2023-03-14

我的问题基本上是这样的--给定这里显示的代码,在试图启动对客户机的响应的管道中还有什么运行?我知道关于该异常的其他问题,但似乎在中间件之后运行的管道中有什么东西导致了异常--它不是由中间件引起的,我认为这是我的场景中的不同之处。

这是一个简单的ASP.NET Core3.0WebSocket echo服务器--没有信号、没有MVC、没有路由、没有静态页面支持等等。除了处理套接字之外,当中间件看到对text/html的请求时,它会发回一个简单的页面(硬编码的字符串)作为echo客户机。

浏览器接收到的内容很好,并且我的异常处理程序没有被触发(这是一个关键点),但是在中间件处理完请求之后,ASP.NET核心会记录异常:

无法设置StatusCode,因为响应已经启动。

代码非常简单:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<WebSocketMiddleware>();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        var webSocketOptions = new WebSocketOptions()
        {
            KeepAliveInterval = TimeSpan.FromSeconds(120),
            ReceiveBufferSize = 4 * 1024
        };
        app.UseWebSockets(webSocketOptions);
        app.UseMiddleware<WebSocketMiddleware>();
    }
}
public class WebSocketMiddleware : IMiddleware
{
    // fields/properties omitted
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        try
        {
            if (context.WebSockets.IsWebSocketRequest)
            {
                // omitted, socket upgrade works normally
            }
            else
            {
                if(context.Request.Headers["Accept"][0].Contains("text/html"))
                {
                    // this works but causes the exception later in the pipeline
                    await context.Response.WriteAsync(SimpleHtmlClient.HTML);
                }
                else
                {
                    // ignore other requests such as favicon
                }
            }
        }
        catch (Exception ex)
        { 
            // code omitted, never triggered 
        }
        finally
        {
            // exception happens here
            await next(context);
        }
    }
}

共有1个答案

须旭
2023-03-14

用户@nkosi的评论是正确的--当我的中间件能够完全处理请求时(将HTTP升级到WS,或者发回echo客户机HTML),它不应该将上下文传递给next委托。但是,在这个非常简单的示例中,其他请求(比如试图检索favicon的浏览器)我的中间件什么也不做,所以解决方案是这样的:

finally
{
    if(!context.Response.HasStarted)
        await next(context);
}
 类似资料: