首页 > 编程语言 >由ASP.NET Core读取Response.Body引发的思考

由ASP.NET Core读取Response.Body引发的思考

时间:2023-04-11 11:13:25浏览次数:44  
标签:Body Core ASP 读取 Stream IHttpResponseBodyFeature ResponseBody public

由ASP.NET Core读取Response.Body引发的思考

 

前言#

    前几天有群友在群里问如何在我之前的文章《ASP.NET Core WebApi返回结果统一包装实践》的时候有点疑问,主要的疑问点就是关于Respouse的读取的问题。在之前的文章《深入探究ASP.NET Core读取Request.Body的正确方式》曾分析过关于Request的读取问题,需要读取Response的场景同样经常遇到,比如读取输出信息或者包装一下输出结果等。无独有偶Response的读取同样存在类似的问题,本文我们便来分析一下如何进行Response的Body读取。

使用方式#

我们在日常的使用中是如何读取流呢?很简单,直接使用StreamReader去读取,方式如下

public override void OnResultExecuted(ResultExecutedContext context)
{
    //操作流之前恢复一下操作位
    context.HttpContext.Response.Body.Position = 0;

    StreamReader stream = new StreamReader(context.HttpContext.Response.Body);
    string body = stream.ReadToEnd();
    _logger.LogInformation("body content:" + body);

    context.HttpContext.Response.Body.Position = 0;
    base.OnResultExecuted(context);
}

代码很简单,直接读取即可,可是这样读取是有问题的会抛出异常System.ArgumentException:“Stream was not readable.”异常信息就是的意思是当前Stream不可读,也就是Respouse的Body是不可以被读取的。关于StreamReader到底和Stream有啥关联,我们在之前的文章深入探究ASP.NET Core读取Request.Body的正确方式一文中有过源码分析,这里就不在赘述了,有兴趣的同学可以自行翻阅,强烈建议在阅读本文之前可以看一下那篇文章,方便更容易了解。
如何解决上面的问题呢?方式也很简单,比如你想在你的程序中保证Response的Body都是可读的,你可以定义一个中间件解决这个问题。

public static IApplicationBuilder UseResponseBodyRead(this IApplicationBuilder app)
{
    return app.Use(async (context, next) =>
    {
        //获取原始的Response Body
        var originalResponseBody = context.Response.Body;
        try
        {
            //声明一个MemoryStream替换Response Body
            using var swapStream = new MemoryStream();
            context.Response.Body = swapStream;
            await next(context);
            //重置标识位
            context.Response.Body.Seek(0, SeekOrigin.Begin);
            //把替换后的Response Body复制到原始的Response Body
            await swapStream.CopyToAsync(originalResponseBody);
        }
        finally
        {
            //无论异常与否都要把原始的Body给切换回来
            context.Response.Body = originalResponseBody;
        }
    });
}

本质就是先用一个可操作的Stream比如咱们这里的MemoryStream替换默认的ResponseBody,让后续对ResponseBody的操作都是针对新的ResponseBody进行操作,完成之后把替换后的ResponseBody复制到原始的ResponseBody。最终无论异常与否都要把原始的Body给切换回来。需要注意的是,这个中间件的位置尽量要放在比较靠前的位置注册,至少也要保证在你所有要操作ResponseBody之前的位置注册。如下所示

var app = builder.Build();
app.UseResponseBodyRead();

源码探究#

通过上面我们了解到了ResponseBody是不可以被读取的,至于为什么呢,这个我们需要通过相关源码了解一下。通过HttpContext类的源码我们可以看到相关定义

public abstract class HttpContext
{
    public abstract HttpResponse Response { get; }
}

这里看到HttpContext本身是个抽象类,看一下它的属性HttpResponse类的定义也是一个抽象类

public abstract class HttpResponse
{
}

由上面可知Response属性是抽象的,所以抽象类HttpResponse必然包含一个子类去实现它,否则没办法直接操作相关方法。这里我们介绍一个网站https://source.dot.net用它可以更轻松的阅读微软类库的源码,比如CLR、ASP.NET Core、EF Core等等,双击一个类或者属性方法可以查找引用和定义它们的地方,非常方便,它的源码都是最新版本的,来源就是GitHub上的相关仓库。找到实例化HttpResponse的为位置在HttpContext的子类DefaultHttpContext类中[点击查看源码

标签:Body,Core,ASP,读取,Stream,IHttpResponseBodyFeature,ResponseBody,public
From: https://www.cnblogs.com/sexintercourse/p/17305530.html

相关文章

  • 解决ModuleNotFoundError: No module named ‘numpy.core._multiarray_umath‘的方法
    1,卸载numpy,pip3uninstasllnumpy2,清华numpy安装,pipinstall-ihttps://pypi.tuna.tsinghua.edu.cn/simple--upgradenumpy   ......
  • ASP.NET Web API]如何Host定义在独立程序集中的Controller
    原文:https://www.cnblogs.com/artech/p/custom-assembly-resolver.html通过《ASP.NETWebAPI的Controller是如何被创建的?》的介绍我们知道默认ASP.NETWebAPI在SelfHost寄宿模式下用于解析程序集的AssembliesResolver是一个DefaultAssembliesResolver对象,它只会提供当前应用程......
  • ASP.NET Core MVC 从入门到精通之接化发(二)
    随着技术的发展,ASP.NETCoreMVC也推出了好长时间,经过不断的版本更新迭代,已经越来越完善,本系列文章主要讲解ASP.NETCoreMVC开发B/S系统过程中所涉及到的相关内容,适用于初学者,在校毕业生,或其他想从事ASP.NETCoreMVC系统开发的人员。 经过前两篇文章的讲解,初步了解ASP.NETCor......
  • 【HMS Core】Health Kit关于订阅消息的资讯
    【问题描述】1.数据跨N天同步,怎么去区分每一天的数据,开始时间和结束时间可以区分吗。会出现一天时间内有多段数据的情况出现吗2.华为健康APP自动同步的频率是多少,凌晨0点0分会把前一天的数据上云吗3.假设我可以在APP自动同步的瞬间点击同步,会不会出现数据重复问题4.针对运动数......
  • 【HMS Core】应用内支付FAQ 6-unknownException、订单编号传入
     【关键字】应用内支付、报错 【问题描述1】收到华为的支付回调通知后,通过通知里面的purchaseToken,调用Order服务验证购买Token时报错​【解决方案】1、报错“6-unknownException”有可能是因为请求头里带的认证token有问题,请检查Authorization字段https://developer.hu......
  • 第9章 使用MVC为移动和客户端应用程序创建Web API(ASP.NET Core in Action, 2nd Editio
    本章包括创建WebAPI控制器以向客户端返回JSON使用属性路由自定义URL使用内容协商生成响应使用[ApiController]属性应用通用约定在前五章中,您已经完成了服务器端渲染ASP.NETCore应用程序的每一层,使用RazorPages将HTML渲染到浏览器。在本章中,您将看到对ASP.NETCore应用程......
  • 第8章 使用标记帮助工具构建表单(ASP.NET Core in Action, 2nd Edition)
    本章包括使用TagHelpers轻松构建表单使用锚标记帮助程序生成URL使用TagHelpers为Razor添加功能在第7章中,您了解了Razor模板以及如何使用它们为应用程序生成视图。通过混合HTML和C#,您可以创建动态应用程序,根据请求、登录用户或您可以访问的任何其他数据显示不同的数据。显......
  • #yyds干货盘点#【愚公系列】2023年04月 .NET CORE工具案例-多语言离线翻译系统
    前言1.在线翻译在线翻译,一般是指在线翻译工具,如百度翻译、阿里翻译1688或Google翻译等。这类翻译工具的作用是利用计算机程序将一种自然语言(源语言)转换为另一种自然语言(目标语言)。其原理是依托海量的互联网数据资源和自然语言处理技术,在数百万篇文档中查找各种模式,以求解最佳......
  • #yyds干货盘点#【愚公系列】2023年04月 .NET CORE工具案例-分布式服务的健康检查系统
    前言1.健康检查系统来源背景互联网产品对用户体验提出了很高的要求,但常常由于技术侧原因,发生服务响应慢或者服务不可用等一系列影响用户体验的问题,导致业务中断,影响收入。影响服务不可用和响应慢的因素很多,可能是服务硬件损坏、光纤被挖断,可能是请求量过大导致数据库CPU负载、磁......
  • Vulnhub之Loly靶机详细测试过程(不同提权方法,利用metasploit工具)
    Loly识别目标主机IP地址─(kali㉿kali)-[~/Desktop/Vulnhub/Loly]└─$sudonetdiscover-ieth1-r192.168.56.0/24Currentlyscanning:192.168.56.0/24|ScreenView:UniqueHosts......