解决ASP.NET Core的中间件无法读取Response.Body的问题

news2024/12/25 1:16:47

概要

本文主要介绍如何在ASP.NET Core的中间件中,读取Response.Body的方法,以便于我们实现更多的定制化开发。本文介绍的方法适用于.Net 3.1 和 .Net 6。

代码和实现

现象解释

首先我们尝试在自定义中间件中直接读取Response.Body,代码如下:

public class GlobalRequestManagementMiddleware : IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            try
            {
                await next(context);
                var reader = new StreamReader(context.Response.Body, Encoding.UTF8);
                var bodyText = await reader.ReadToEndAsync();
            }
            catch (Exception)
            {
                throw;
            }
        }
    }

我们会得到一个异常消息,表示Response.Body是一个不可读的Stream流。
在这里插入图片描述
我们添加更多的调试信息,查看Response.Body的具体属性:

 public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
   try
   {
       await next(context);
       Console.WriteLine("CanRead is " + context.Response.Body.CanRead);
       Console.WriteLine("CanSeek is " + context.Response.Body.CanSeek);
       Console.WriteLine("CanWrite is " + context.Response.Body.CanWrite);
       var reader = new StreamReader(context.Response.Body, Encoding.UTF8);
       var bodyText = await reader.ReadToEndAsync();

   }
   catch (Exception)
   {
       throw;
   }
}

输出结果如下:

在这里插入图片描述
Response.Body是一个不可读,不可查找,但是可写的Stream,CanRead,CanSeek和CanWrite全部是只读属性,不可修改。

解决方案

从Response.Body本身来解决这个问题,已经基本不可能了。因为该Stream已经被标记为不可读,并且不可修改。

我们变换解决思路,既然这个Stream无法使用,那我们就在其进入其它中间件,过滤器和Action之前,将其替换为可读和可写的普通内存流。代码如下:

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
 {
     using ( var bodyStream = new MemoryStream())
     {
         Stream originalBody = context.Response.Body;
         context.Response.Body = bodyStream ;
         await next(context);
         bodyStream.Position = 0;
         var reader = new StreamReader(context.Response.Body, Encoding.UTF8);
         var bodyText = await reader.ReadToEndAsync();
         Console.WriteLine("bodyText is " + bodyText);
         bodyStream.Position = 0;
         await bodyStream.CopyToAsync(originalBody);
         context.Response.Body = originalBody;
     }
 }
  1. 用普通的MemoryStream替代原有Response.Body中的Stream;
  2. 使用MemoryStream 去接收中间件后面操作产生的操作结果;
  3. 读取MemoryStream中的操作结果;
  4. 重置MemoryStream,以方便后面的操作读取;
  5. Response.Body虽然是不可读的,但是可写,我们可以将中间件后续操作中的操作结果写入最初的Response.Body中;
  6. 将context.Response.Body替换为最初的Stream流。

用上述方法,我们就可以读取甚至修改Response.Body中的内容。

我们调用一个Post请求,查看我们自定义的Middleware和后面的操作是否可以正常完成:

[HttpPost("{id}")]
public Student Post([FromBody] Student student)
{
    return student;
}

执行结果如下:

在这里插入图片描述

在这里插入图片描述
Body的内容在中间件中被成功读出,Post请求成功的将Student对象返回。

附录

  public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1059568.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Appleid苹果账号自动解锁改密(自动解锁二验改密码)

目前该项目能实现以下功能: 多用户使用,权限控制多账号管理账号分享页,支持设置密码、有效期、自定义HTML内容自动解锁与关闭二步验证自动/定时修改密码自动删除Apple ID中的设备代理池与Selenium集群,提高解锁成功率允许手动触发…

先输入列,再输入行

想要的表格行数和列数是 5 行 5 列,以下是相应的代码实现: # 定义表格行数和列数 rows 5 cols 5# 创建一个二维列表作为表格 table [[ for j in range(cols)] for i in range(rows)]print("请输入表格数据:")while True:# 获取…

Python无废话-办公自动化Excel读取操作

openpyxl模块介绍 openpyxl是一个用于处理Excel文件的Python库,用于读取/写入Excel2010 xlsx/xlsm/xltx/xltm文件(不支持xls格式)。通过使用openpyxl库,可 以轻松地在Python程序中实现对Excel文件的操作。 openpyxl 安装 方式1:使用pip 命令安装&…

操作系统学习笔记1

文章目录 1、OS的一个宏观比喻2、OS的目的和功能3、OS的发展4、OS的运行机制5、OS的特征6、OS的体系结构 参考视频:操作系统 1、OS的一个宏观比喻 2、OS的目的和功能 3、OS的发展 4、OS的运行机制 中断、系统调用、异常。 5、OS的特征 6、OS的体系结构

【逐步剖C++】-第二章-C++类和对象(下)

前言:本文是对类和对象知识点的最后一篇总结,前两篇的链接如下: 【逐步剖C】-第二章-C类和对象(上) 【逐步剖C】-第二章-C类和对象(中) 这三篇加起来就是笔者学习在类和对象中的所有总结了&…

计算机网络网络层、应用层、数据链路层协议详解

目录 一、计算机网络 二、网络层 三、应用层 四、数据链路层 一、计算机网络 计算机网络是将多台计算机和其他网络设备通过通信链路连接起来,以实现数据交换和资源共享的系统。它是现代信息社会的基础设施之一,为人们提供了快速、可靠、安全的数据传…

学校项目培训之Carla仿真平台之Carla学习内容

一、Blender Blender入门:https://www.bilibili.com/video/BV1fb4y1e7PD/ Blender导入骨骼:https://www.bilibili.com/video/BV1hc41157nL 做一个车:https://www.bilibili.com/video/BV1hY411q7w2 二、Roadrunner RoadRunner Scenario…

Flink状态管理与检查点机制

1.状态分类 相对于其他流计算框架,Flink 一个比较重要的特性就是其支持有状态计算。即你可以将中间的计算结果进行保存,并提供给后续的计算使用: 具体而言,Flink 又将状态 (State) 分为 Keyed State 与 Operator State: 1.1 算子状态 算子状态 (Operator State):顾名思义…

计组—— I/O系统

📕:参考王道课件 目录 一、I/O系统的基本概念 1.什么是“I/O”? ​编辑2.主机如何和I/O设备进行交互? 3.I/O控制方式 (1)程序查询方式 (2)程序中断方式 (3&#x…

【MATLAB源码-第41期】基于压缩感知算法的OFDM系统信道估计和LS算法对比仿真。

操作环境: MATLAB 2013b 1、算法描述 压缩感知(Compressed Sensing, CS)是一种从稀疏或可压缩信号中重构完整信号的数学理论和技术。下面详细介绍压缩感知和它在OFDM信道估计中的应用。 1. 压缩感知基本概念 在传统采样理论中&#xff0…

数字电路逻辑与设计 之循环码和 移存码

有发现错误的能力,不能纠正 只能检查单次的错误,不能完全抗干扰 可以按照上面的方法来循环构造 移存码可以通过前推后推来实现

pytorch_神经网络构建1

文章目录 pytorch简介神经网络基础分类问题分析:逻辑回归模型逻辑回归实现多层神经网络多层网络搭建保存模型 pytorch简介 为什么神经网络要自定义数据类型torch.tensor? tensor可以放在gpu上训练,支持自动求导,方便快速训练,同时支持numpy的运算,是加强版,numpy不支持这些 为…

C++项目:【高并发内存池】

文章目录 一、项目介绍 二、什么是内存池 1.池化技术 2.内存池 3.内存池主要解决的问题 4.malloc 三、定长的内存池 四、高并发内存池整体框架设计 1.高并发内存池--thread cache 1.1申请内存: 1.2释放内存: 1.3用TLS实现thread cache无锁访…

GD32F10 串口通信

1. 什么是通信 通信,指人与人或人与自然之间通过某种行为或媒介进行的信息交流与传递,从广义上指需要信息的双方或多方在不违背各自意愿的情况下采用任意方法,任意媒质,将信息从某方准确安全地传送到另方。通信双方如果想正确传输…

SystemUI导航栏

SystemUI导航栏 1、系统中参数项1.1 相关开关属性2.2 属性设置代码 2、设置中设置“三按钮”导航更新流程2.1 属性资源覆盖叠加2.2 SystemUI导航栏接收改变广播2.3 SystemUI导航栏布局更新2.4 时序图 android13-release 1、系统中参数项 1.1 相关开关属性 设置->系统->…

C++算法 —— 动态规划(9)完全背包问题

文章目录 1、动规思路简介2、完全背包【模板】3、零钱兑换4、零钱兑换Ⅱ5、完全平方数 背包问题需要读者先明白动态规划是什么,理解动规的思路,并不能给刚接触动规的人学习。所以最好是看了之前的动规博客,以及01背包博客,才能看完…

学习C++语言可以适用于哪些方面

学习C可以让你具备开发各种类型软件和系统的能力,它是一种通用的、高性能的编程语言。以下是学习C的一些用途和应用领域: 系统开发:C被广泛用于操作系统、驱动程序和嵌入式系统的开发。通过学习C,你可以编写底层的系统代码&#x…

java大富翁

一、 概述 Java Swing大富翁游戏是一个经典的大富翁桌面游戏的简单实现,使用Java Swing库创建。该游戏允许玩家在一个虚拟棋盘上掷骰子,购买和升级属性,赚取租金和尽量丰富自己。这个文档说明将介绍如何安装和运行游戏,以及游戏规…

【C++】C++11——右值引用和移动语义、左值引用和右值引用、右值引用使用场景和意义、完美转发、新的类功能

文章目录 C115.右值引用和移动语义5.1左值引用和右值引用5.2左值引用与右值引用比较5.3右值引用使用场景和意义5.4右值引用引用左值及其一些更深入的使用场景分析5.5完美转发 6.新的类功能 C11 5.右值引用和移动语义 右值引用是C11引入的一个新特性,用于支持移动语义…

冯诺依曼体系结构与进程的初步理解

目录 一,冯诺依曼体系结构 1.是什么?特点 2.为什么? 二,操作系统 三,进程 1.什么是进程? 2.查看进程 3.进程的管理 4.fork()创建子进程 1.fork()简介 2.fork()干了啥 3.fork()为什么会有两个返回…