读取 Filter 中的 Response.Body 流

No1*_*ver 9 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 (StreamReader sr = new StreamReader(context.HttpContext.Response.Body))
        {
            Console.WriteLine(sr.ReadToEnd());
        }

        base.OnResultExecuted(context);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果-异常:

流不可读。

进一步的调查使我发现流 ( context.HttpContext.Response) 具有这些值:

  1. 可以读取 = false
  2. 可以寻找=假

这可以解释为什么它无法读取正文......

怎么解决?

itm*_*nus 4

不知道为什么你需要这样做。context.Result是 的一个实例IActionResult,您可以随意操纵它。如果你确实想阅读Response.Body,可以做一些 hacky 的事情。

由于默认值Response.Body不可读Stream,为了使正文可读,我们需要劫持响应,即Body用我们自己的实例Stream替换:

  1. 我们可以在动作执行之前动态创建一个全新的内存流,并劫持默认Response.Body流。
  2. 当执行操作时,使用 a 读取流StreamReader,做一些工作,然后设置Response.Body=your new stream.

使用普通内存流劫持 是安全的,Response.Body因为 的类型Body是普通的Stream

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

出于测试目的,我创建了一个操作方法:

[MyCustomFilter]
public IActionResult Index()
{
    return Ok("it wooooooooorks");
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • EnableRewind 或现在发布的 EnableBuffering 只能用于请求,不能用于响应。 (11认同)
  • 无需摆弄您自己的实现。只需调用“Request.EnableRewind();”(ASP.NET Core 2.0 及更高版本),“Request.Stream”将被替换为可回滚版本。与您的解决方案一样,人们应该始终意识到这样做对内存/性能的影响:https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.internal.bufferinghelper.enablerewind?查看=aspnetcore-2.1 (4认同)