如何在ASP.NET核心中间件中直接设置文件流的响应体? [英] How to directly set response body to a file stream in ASP.NET Core middleware?

查看:14
本文介绍了如何在ASP.NET核心中间件中直接设置文件流的响应体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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的方法有什么问题吗?

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

更新(另一个示例):简单的MemoryStream赋值也不起作用(空响应):

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

推荐答案

  1. 不是。您永远不能直接这样做。

    请注意,context.Response.Body是对对象(HttpResponseStream)的引用,initialized before它在HttpContext中可用。假设所有字节都写入此原始流。如果您通过context.Response.Body = a_new_StreamBody更改为引用(指向)新的流对象,则原始的Stream根本不会更改。

    此外,如果您查看ASP.NET Core的源代码,您会发现团队总是将包装流复制到末尾的原始正文流,而不是使用简单的替换(除非他们正在使用模拟的流进行单元测试)。例如SPA Prerendering middleware源代码:

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

    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. 作为漫游,您可以将字节复制到原始流,如下所示:

    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);
        }
    }
    

    或者如果您喜欢劫持原始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;
        }
    

这篇关于如何在ASP.NET核心中间件中直接设置文件流的响应体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆