如何读取 Response 主体并将其更改为重写的 Controller 的 OnActionExecuted 方法

问题描述 投票:0回答:1

我需要将一些信息附加到控制器每个操作的每个 JSON 答案中。为此,我使基本控制器继承自标准 MVC

Controller
类。 我尝试这样。但我发现
ArgumentException
带有这样的消息:“流不可读。”当
ActionResult
对象将数据写入正文时,可能流已关闭。我能做些什么?

public override void OnActionExecuted(ActionExecutedContext context)
{
    var respApi = new ResponseApiDTO();
    respApi.Comment = "You could!!!";
    JObject jRespApi = JObject.FromObject(respApi);
    Stream bodyStream = context.HttpContext.Response.Body;
    JObject jbody;

    context.Result = Json(jbody);
    using( var rd = new StreamReader(bodyStream))
    {
        string bodyText = rd.ReadToEnd();
        jbody = (JObject)JsonConvert.DeserializeObject(bodyText);
        jbody.Add(jRespApi);
        context.Result = Json(jbody);
    }
}
c# asp.net-web-api asp.net-core asp.net-core-webapi
1个回答
5
投票

我找到了解决办法。在管道中执行 MVC 步骤时,我们需要用

MemoryStream
对象替换 Body 流。然后我们必须将原始流对象返回到
Response.Body

// Extension method used to add the middleware to the HTTP request pipeline.
public static class BufferedResponseBodyExtensions
{
    public static IApplicationBuilder UseBufferedResponseBody(this IApplicationBuilder builder)
    {
        return builder.Use(async (context, next) =>
        {
            using (var bufferStream = new MemoryStream())
            {
                var orgBodyStream = context.Response.Body;
                context.Response.Body = bufferStream;

                await next();//there is running MVC
                   
                bufferStream.Seek(0, SeekOrigin.Begin);
                await bufferStream.CopyToAsync(orgBodyStream);    
                context.Response.Body = orgBodyStream;
            }
        });
    }
}

然后将其包含到管道中。类启动,方法配置。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{   
    ...
    app.UseBufferedResponseBody();
    app.UseMvc();           
    ...
}

替换响应正文流后,您可以通过结果过滤器读取和修改正文内容。

 public class ResultFilterAttribute : Attribute, IResultFilter
 {
     public async void OnResultExecuted(ResultExecutedContext context)
     {
         Stream bodyStream = context.HttpContext.Response.Body;
         bodyStream.Seek(0, SeekOrigin.Begin);
         string bodyText = rd.ReadToEnd();
     }
 }

此属性必须应用于目标控制器类。

© www.soinside.com 2019 - 2024. All rights reserved.