
在我最初的答复中,我完全误解了这个问题,并以为张贴人在问如何阅读
Request.Body文章
Response.Body。我将保留原来的答案,以保留历史记录,但也将对其进行更新,以显示正确阅读后如何回答该问题。
原始答案
如果要缓冲流支持多次读取,则需要设置
context.Request.EnableRewind()
理想情况下,在任何需要读取正文的中间件中尽早进行此 *** 作。
因此,例如,您可以将以下代码放在
ConfigureStartup.cs文件的方法的开头:
app.Use(async (context, next) => { context.Request.EnableRewind(); await next(); });在启用快退之前,与关联的流
Request.Body是仅转发流,不支持第二次查找或读取该流。这样做是为了使请求处理的默认配置尽可能轻巧和高效。但是,一旦启用倒带,流将升级为支持多次查找和读取的流。您可以通过在调用之前和之后设置断点
EnableRewind并观察
Request.Body属性来观察此“升级”
。因此,例如
Request.Body.CanSeek将从
false变为
true。
更新 :从ASP.NET Core
2.1开始,
Request.EnableBuffering()可以将其升级
Request.Body到
FileBufferingReadStream类似的名称,
Request.EnableRewind()并且由于
Request.EnableBuffering()它位于公共名称空间而不是内部名称空间中,因此它应优先于EnableRewind()使用。(感谢@ArjanEinbu指出)
然后,例如,要读取主体流,可以执行以下 *** 作:
string bodyContent = new StreamReader(Request.Body).ReadToEnd();
但是,不要将
StreamReader创建内容包装在using语句中,否则它将在using块结束时关闭底层主体流,并且请求生命周期中的稍后代码将无法读取主体。
同样为了安全起见,遵循上述读取正文内容的代码行以及此代码行以将正文的流位置重置回0可能是个好主意。
request.Body.Position = 0;
这样,请求生命周期中稍后的任何代码都可以找到请求.Body处于尚未被读取的状态。
更新的答案
抱歉,我原本误读了您的问题。将关联流升级为缓冲流的概念仍然适用。但是,您必须手动执行此 *** 作,但我不知道任何内置的.Net
Core功能,该功能使您可以在编写
EnableRewind()请求后立即读取响应流,从而使开发人员在读取请求流后重新读取该请求流。
您的“
hacky”方法可能完全合适。您基本上是在将无法寻找的流转换为可以寻找的流。最终,必须将
Response.Body流与已缓冲并支持查找的流换出。这是中间件的另一种实现方法,但是您会注意到它与您的方法非常相似。但是,我确实选择使用finally块作为添加保护,以将原始流放回上,
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; } }欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)