繁体   English   中英

准ASP.NET Core中间件项目中的“响应已经开始”异常

[英]“Response has already started” exception in a bare-bones ASP.NET Core middleware project

我的问题基本上是这样的-给定此处显示的代码,试图启动对客户端响应的管道中还有哪些其他内容? 我知道有关该异常的其他问题,但似乎在中间件引起异常之后运行的管道中有一些东西–它不是由中间件引起的,我认为这是我的情况的与众不同。

这是一个准系统的ASP.NET Core 3.0 WebSocket回显服务器-没有SignalR,没有MVC,没有路由,没有静态页面支持等。除了处理套接字,当中间件看到发送的text/html请求时返回一个简单页面(硬编码字符串)作为回显客户端。

浏览器可以很好地接收内容,并且不会触发我的异常处理程序(关键点),但是在我的中间件处理完请求之后,ASP.NET Core记录了异常:

无法设置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);
        }
    }
}

我以为问题可能出在我对WriteAsync使用上,但是如果我还在其他位置设置HTTP状态而没有其他输出(例如在catch块中设置HTTP 500),这似乎会发生。 如果我通过在中间件中的第一个语句中添加一个throw作为逐步处理故意导致的异常,那么它将到达发生“已经开始”异常的finally位置。

那么给定Startup类,还有什么尝试在管道中产生输出呢?

编辑:堆栈跟踪,最后引用的第91行是finally块中的await next(context)

System.InvalidOperationException:无法设置StatusCode,因为响应已经开始。 在Microsoft.AspNetCore.Server处Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32值)处Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(字符串值) .Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32值)在Microsoft.AspNetCore.Http.DefaultHttpResponse.set_StatusCode(Int32值)在Microsoft.AspNetCore.Builder.ApplicationBuilder。< > c.b__18_0(HttpContext上下文)在KestrelWebSocketServer.WebSocketMiddleware.InvokeAsync(HttpContext上下文,RequestDelegate接下来)在Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.C:\\ Source \\ WebSocketExample \\ KestrelWebSocketServer \\ WebSocketMiddleware.cs:第91行。<> c__DisplayClass5_1。 <b__1> d.MoveNext()---从上一个引发异常的位置开始的堆栈跟踪-在Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests [TContext](IHttpApp lication`1申请)

用户@Nkosi的评论是正确的-当我的中间件能够完全处理请求(将HTTP升级到WS或发送回显客户端HTML)时,它不应将上下文传递给next委托。 但是,在这个非常简单的示例中,我的中间件没有执行任何其他请求(例如尝试检索Favicon的浏览器),因此解决方案是:

finally
{
    if(!context.Response.HasStarted)
        await next(context);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM