下面的示例代码将文件流写入ASP.NET Core中间件中的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()));
最佳答案
请注意,
context.Response.Body
是对对象( HttpResponseStream
)的引用,该对象是 initialized before,它可以在HttpContext
中使用。假定所有字节都写入此原始流中。如果您通过Body
将context.Response.Body = a_new_Stream
更改为引用(指向)新的流对象,则原始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);
}
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-core - 如何在ASP.NET Core中间件中直接将响应主体设置为文件流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58653564/