如何在 ASP.NET Core 中间件中直接将响应正文设置为文件流?

2023-11-27

下面的示例代码将文件流写入Response.Body在 ASP.NET Core 中间件中不起作用(发出空响应):

public Task Invoke(HttpContext context)
{
    context.Response.ContentType = "text/plain";

    using (var fs = new FileStream("/valid-path-to-file-on-server.txt", FileMode.Open)
    using (var sr = new StreamReader(fs))
    {
        context.Response.Body = sr.BaseStream;
    }

    return Task.CompletedTask;
}

任何想法这种直接设置的方法可能有什么问题context.Response.Body?

注意:管道中的任何下一个中间件都将被跳过,不再进行进一步处理。

Update(另一个例子):一个简单的MemoryStream分配也不起作用(空响应):

context.Response.Body = new MemoryStream(Encoding.UTF8.GetBytes(DateTime.Now.ToString()));

  1. 不,你永远不能直接这样做。

    注意context.Response.Body是对对象的引用(HttpResponseStream) 那是之前初始化过它可以在HttpContext。假设所有字节都写入到这个原始 Stream 中。如果您更改Body参考(point to) 一个新的流对象context.Response.Body = a_new_Stream, 原本的Stream根本没有改变。

    另外,如果你查看源代码ASP.NET Core,你总会找到团队copy最后将包装器流添加到原始主体流,而不是进行简单的替换(除非它们使用模拟流进行单元测试)。例如,SPA 预渲染中间件源代码:

        finally
        {
            context.Response.Body = originalResponseStream;
            ...
    

    And the ResponseCachingMiddleware源代码:

        public async Task Invoke(HttpContext httpContext)
        {
            ...
            finally
            {
                UnshimResponseStream(context);
            }
            ...
        }
    
        internal static void UnshimResponseStream(ResponseCachingContext context)
        {
            // Unshim response stream
            context.HttpContext.Response.Body = context.OriginalResponseStream;
    
            // Remove IResponseCachingFeature
            RemoveResponseCachingFeature(context.HttpContext);
        }
    
  2. 作为漫游,您可以copy原始流的字节如下:

    public async Task Invoke(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        using (var fs = new FileStream("valid-path-to-file-on-server.txt", FileMode.Open))
        {
            await fs.CopyToAsync(context.Response.Body);
        }
    }
    

    或者如果你愿意hijack原始的HttpResponseStream使用您自己的流包装器:

        var originalBody = HttpContext.Response.Body;
        var ms = new MemoryStream();
        HttpContext.Response.Body = ms;
        try
        {
            await next();
            HttpContext.Response.Body = originalBody;
            ms.Seek(0, SeekOrigin.Begin);
            await ms.CopyToAsync(HttpContext.Response.Body);
        }
        finally
        {
            response.Body = originalBody;
        }
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 ASP.NET Core 中间件中直接将响应正文设置为文件流? 的相关文章

随机推荐