C# 正在读取筛选器中的Response.Body流
我编写了在服务器方法调用后运行的过滤器,并将其内容打印到控制台。代码是用ASP.NET core v2.1编写的:C# 正在读取筛选器中的Response.Body流,c#,asp.net,asp.net-web-api,asp.net-core,C#,Asp.net,Asp.net Web Api,Asp.net Core,我编写了在服务器方法调用后运行的过滤器,并将其内容打印到控制台。代码是用ASP.NET core v2.1编写的: public class MyCustomFilter : ActionFilterAttribute { public override void OnResultExecuted(ResultExecutedContext context) { // ERROR on the next line! using (StreamRe
public class MyCustomFilter : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext context)
{
// ERROR on the next line!
using (StreamReader sr = new StreamReader(context.HttpContext.Response.Body))
{
Console.WriteLine(sr.ReadToEnd());
}
base.OnResultExecuted(context);
}
}
结果-例外:
流不可读
进一步的研究表明,流(context.HttpContext.Response
)具有以下值:
如何解决?这完全取决于你想要实现什么。 如果您想获得响应值或只是想查看结果,可以使用
context.Result or context.Result.Value
如果您想要修改响应或只是记录整个响应,您应该使用中间件
这是一个很好的例子
希望它能帮上忙。我不知道你为什么要这样做
context.Result
是IActionResult
的一个实例,您可以随意操作它。如果您确实想阅读Response.Body
,可以做一些黑客行为
由于默认的响应.Body
不是可读的流
,为了使Body可读,我们需要劫持响应,即用我们自己的流
实例替换Body
:
Response.Body
流李>
StreamReader
读取流,做一些工作,并设置响应。Body=您的新流
响应.Body
是安全的,因为Body
的类型是普通流
public class MyCustomFilter : ActionFilterAttribute
{
private MemoryStream responseBody ;
public override void OnActionExecuting(ActionExecutingContext context){
this.responseBody=new MemoryStream();
// hijack the real stream with our own memory stream
context.HttpContext.Response.Body = responseBody;
}
public override void OnResultExecuted(ResultExecutedContext context)
{
responseBody.Seek(0, SeekOrigin.Begin);
// read our own memory stream
using (StreamReader sr = new StreamReader(responseBody))
{
var actionResult= sr.ReadToEnd();
Console.WriteLine(actionResult);
// create new stream and assign it to body
// context.HttpContext.Response.Body = ;
}
// no ERROR on the next line!
base.OnResultExecuted(context);
}
}
出于测试目的,我创建了一个操作方法:
[MyCustomFilter]
public IActionResult Index()
{
return Ok("it wooooooooorks");
}
使用Actionfilter而不是中间件:
var resultnext = await next();
var objectResult = resultnext.Result as ObjectResult;
var resultValue = objectResult.Value;
无需对您自己的实现进行修改。只需调用
Request.EnableRewind()
(ASP.NET Core 2.0及更高版本)和请求.Stream
将替换为可倒带版本。与您的解决方案一样,人们应该始终意识到这样做对内存/性能的影响:@Tseng我没有意识到这一点。非常感谢,你的解决方案比我的好得多。@Tseng Hi,很抱歉打扰你。但是我不知道如何为Response
启用倒带,就像Request.EnableRewind()
。你能帮我个忙吗?谢谢。只需调用Request.EnableRewind()
,但您必须在从请求读取任何内容之前执行此操作。如果其他中间件已经开始从中读取,那么调用EnableRewind()
就太晚了EnableRewind()
是一种扩展方法(如链接文档中所示),您需要声明名称空间导入以使其工作:使用Microsoft.AspNetCore.Http.Internal代码>。但是要小心使用它,它是一个所谓的“pubinternal”(具有公共访问器的内部API),意味着将来可能会发生(中断)更改EnableRewind,或者启用缓冲现在发布的方式,因为它仅可用于请求,而不可用于响应。