替换ASP.NET Core 1.0中间件中的响应流

时间:2016-07-09 19:35:07

标签: asp.net-core asp.net-core-1.0 asp.net-core-middleware

我想在我的ASP.NET Core 1.0项目中编写自定义中间件,它将取代原始框架的Http响应流到我自己的,所以我将能够对它执行读/寻/写操作(首先在进一步的代码中,即在“动作”或“过滤器”中,原始流上无法实现2。

我已经开始使用以下代码:

public class ReplaceStreamMiddleware
{
    protected RequestDelegate NextMiddleware;

    public ReplaceStreamMiddleware(RequestDelegate next)
    {
        NextMiddleware = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {       
        using (var responseStream = new MemoryStream())
        {
            var fullResponse = httpContext.Response.Body;
            httpContext.Response.Body = responseStream;
            await NextMiddleware.Invoke(httpContext);
            responseStream.Seek(0, SeekOrigin.Begin);
            await responseStream.CopyToAsync(fullResponse);
        }   
    }
}

以下代码的问题是,在调用fullResponse有时 await responseStream.CopyToAsync(fullResponse);已关闭,因此它会引发异常无法访问已关闭的流。

当我在浏览器中加载页面然后在完全加载之前刷新时,很容易发现这种奇怪的行为。

我想知道:

  1. 为什么会这样?
  2. 如何预防?
  3. 我的解决方案是一个好主意还是有另一种方法可以替换响应流?

1 个答案:

答案 0 :(得分:7)

例外不是来自HttpContext。它来自您的一个代码的来电者:

您没有在MemoryStream中恢复原始回复流。因此,无论谁调用您的中间件,都会收回已关闭的app.Use(async (httpContext, next) => { using (var memoryResponse = new MemoryStream()) { var originalResponse = httpContext.Response.Body; try { httpContext.Response.Body = memoryResponse; await next.Invoke(); memoryResponse.Seek(0, SeekOrigin.Begin); await memoryResponse.CopyToAsync(originalResponse); } finally { // This is what you're missing httpContext.Response.Body = originalResponse; } } }); app.Run(async (context) => { context.Response.ContentType = "text/other"; await context.Response.WriteAsync("Hello World!"); });

这是一些有效的代码:

{{1}}