gpt4 book ai didi

c# - 如何读取 ASP.NET Core Response.Body?

转载 作者:IT王子 更新时间:2023-10-29 03:51:50 30 4
gpt4 key购买 nike

我一直在努力从 ASP.NET Core 操作中获取 Response.Body 属性,而我能够确定的唯一解决方案似乎不是最佳解决方案。该解决方案需要用 MemoryStream 换出 Response.Body,同时将流读入字符串变量,然后在发送给客户端之前将其换回。在下面的示例中,我试图在自定义中间件类中获取 Response.Body 值。出于某种原因,Response.Body 是 ASP.NET Core 中的一个 set 唯一属性?我只是在这里遗漏了什么,还是这是一个疏忽/错误/设计问题?有没有更好的方法来阅读 Response.Body

当前(次优)解决方案:

public class MyMiddleWare
{
private readonly RequestDelegate _next;

public MyMiddleWare(RequestDelegate next)
{
_next = next;
}

public async Task Invoke(HttpContext context)
{
using (var swapStream = new MemoryStream())
{
var originalResponseBody = context.Response.Body;

context.Response.Body = swapStream;

await _next(context);

swapStream.Seek(0, SeekOrigin.Begin);
string responseBody = new StreamReader(swapStream).ReadToEnd();
swapStream.Seek(0, SeekOrigin.Begin);

await swapStream.CopyToAsync(originalResponseBody);
context.Response.Body = originalResponseBody;
}
}
}

尝试使用 EnableRewind() 的解决方案:这仅适用于 Request.Body,不适用于 Response.Body。这会导致从 Response.Body 中读取一个空字符串,而不是实际的响应正文内容。

Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifeTime)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();

app.Use(async (context, next) => {
context.Request.EnableRewind();
await next();
});

app.UseMyMiddleWare();

app.UseMvc();

// Dispose of Autofac container on application stop
appLifeTime.ApplicationStopped.Register(() => this.ApplicationContainer.Dispose());
}

MyMiddleWare.cs

public class MyMiddleWare
{
private readonly RequestDelegate _next;

public MyMiddleWare(RequestDelegate next)
{
_next = next;
}

public async Task Invoke(HttpContext context)
{
await _next(context);
string responseBody = new StreamReader(context.Request.Body).ReadToEnd(); //responseBody is ""
context.Request.Body.Position = 0;
}
}

最佳答案

在我最初的回复中,我完全误解了这个问题,并认为发帖者在问如何阅读 Request.Body 但他问的是如何阅读 Response.Body。我将保留我原来的答案以保留历史,但也会更新它以显示在正确阅读后我将如何回答问题。

原始答案

如果你想要一个支持多次读取的缓冲流你需要设置

   context.Request.EnableRewind()

理想情况下,在任何东西需要读取正文之前,尽早在中间件中执行此操作。

例如,您可以将以下代码放在 Startup.cs 文件的 Configure 方法的开头:

        app.Use(async (context, next) => {
context.Request.EnableRewind();
await next();
});

在启用 Rewind 之前,与 Request.Body 关联的流是一个只向前的流,不支持第二次查找或读取流。这样做是为了使请求处理的默认配置尽可能轻量级和高性能。但是一旦启用倒带,流就会升级为支持多次查找和读取的流。您可以通过在调用 EnableRewind 之前和之后设置断点并观察 Request.Body 属性来观察此“升级”。因此,例如 Request.Body.CanSeek 将从 false 更改为 true

更新:从 ASP.NET Core 2.1 开始,Request.EnableBuffering() 可用,它将 Request.Body 升级为 FileBufferingReadStream 就像 Request.EnableRewind() 并且因为 Request.EnableBuffering() 在公共(public)命名空间而不是内部命名空间中,所以它应该优于 EnableRewind (). (感谢@ArjanEinbu 指出)

然后要读取正文流,您可以这样做:

   string bodyContent = new StreamReader(Request.Body).ReadToEnd();

不要将 StreamReader 创建包装在 using 语句中,否则它将在 using block 结束时关闭底层主体流,并且请求生命周期中稍后的代码将无法读取 body 。

同样为了安全起见,最好遵循上面这行读取正文内容的代码,用这行代码将正文的流位置重置回 0。

request.Body.Position = 0;

这样,请求生命周期后期的任何代码都会找到 request.Body,就像它还没有被读取一样。

更新的答案

抱歉,我最初误读了您的问题。将关联流升级为缓冲流的概念仍然适用。但是,您必须手动执行此操作,我不知道有任何内置的 .Net Core 功能可以让您在以 EnableRewind() 让开发人员重新读取请求的方式编写后读取响应流读取后流式传输。

您的“hacky”方法可能完全合适。您基本上是在将无法搜索的流转换为可以搜索的流。在一天结束时,Response.Body 流必须被缓冲并支持搜索的流换出。这是使用中间件执行此操作的另一种方法,但您会注意到它与您的方法非常相似。然而,我确实选择使用 finally block 作为将原始流放回 Response.Body 的附加保护,并且我使用了流的 Position 属性而不是 Seek 方法,因为语法简单一些,但效果与您的方法没有什么不同。

public class ResponseRewindMiddleware 
{
private readonly RequestDelegate next;

public ResponseRewindMiddleware(RequestDelegate next) {
this.next = next;
}

public async Task Invoke(HttpContext context) {

Stream originalBody = context.Response.Body;

try {
using (var memStream = new MemoryStream()) {
context.Response.Body = memStream;

await next(context);

memStream.Position = 0;
string responseBody = new StreamReader(memStream).ReadToEnd();

memStream.Position = 0;
await memStream.CopyToAsync(originalBody);
}

} finally {
context.Response.Body = originalBody;
}

}
}

关于c# - 如何读取 ASP.NET Core Response.Body?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43403941/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com