AspNetCore中的中间件详解【超详细】

news2024/11/19 13:33:15

1 什么叫做中间件?

ASP.NET Core处理请求的方式看做是一个管道,中间件是组装到应用程序管道中用来处理请求和响应的组件。通常是一个可重用的类方法
每个中间件可以:
(1)选择是否将请求传递给管道中的下一个组件。
(2)可以在调用管道中的下一个组件之前和之后执行业务逻辑。
在这里插入图片描述

其中关于请求管道配置的一个重要方法在startup中的Configure(IApplicationBuilder app, IWebHostEnvironment env)方法。可用Use、Map、Run方法来配置需要使用的中间件。通常使用
IApplicationBuilder的拓展方法来配置请求管道,加入指定的中间件。

IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
中间件类的本质其实是委托类

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //判断是否为开发环境
            if (env.IsDevelopment())
            {
                //使用异常开发页面中间件
                app.UseDeveloperExceptionPage();
            }

            //静态文件中间件
            app.UseStaticFiles();

            //HTTP请求转HTTPS请求
            app.UseHttpsRedirection();

            //身份验证
            app.UseAuthentication();

            //相较于netcore2来说,Routing 中间件是拆分出来的,原来是属于MVC中间件的一部分
            app.UseRouting();

            //端点中间件,请求处理路径,结合Routing中间件一起使用的
            app.UseEndpoints(endpoints =>
            {
                //当请求"/"时,响应输出HelloWorld【可通过lamda表达式进行配置】
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });

                //请求路径匹配到 /home/index/1 这种路径时,将会到指定的handler处理器上,默认会处理到
                endpoints.MapControllerRoute("default","/{controller=home}/{action=index}/{id?}");
            });

        }

2 请求短路与中间件顺序

请求会按照顺序依次经过每个加入管道的中间件,值得注意的是,中间件可以决定是否将请求交给下一个委托,当中间件拒绝将请求传递到下一个中间件时,叫做请求短路,可以避免不必要的工作。
中间件的执行与调用的顺序有关,在响应式以相反的顺序返回。请求在每一步都有可能短路,所以需要正确的添加中间件,如异常处理的中间件,需要放在请求管道的前面,这样就可以一开始捕获异常,以及后面中间件中可能发生的异常,做出返回处理。
在这里插入图片描述

3 中间件配置方法Use、Run、Map

ASP.NET 中的核心请求管道是通过一个个请求委托串联而来的,具体是通过IApplicationBuilder的Use、Run、Map方法来实现的。

在讲解中间件配置方法之前,需要了解什么是RequestDelegate、和代码语言描述的中间件Func<RequestDelegate, RequestDelegate> middleware

    //一个能处理请求的方法
    public delegate Task RequestDelegate(HttpContext context);


   //中间件原生定义,委托,输入是一个RequestDelegate,输出也是一个RequestDelegate,
    Func<RequestDelegate, RequestDelegate> middleware = new Func<RequestDelegate, RequestDelegate>((RequestDelegate requestdelegate) =>
        {
            return new RequestDelegate(async (context) =>
            {
                await context.Response.WriteAsync("接收1个带RequestDelegate类型的参数,返回RequestDelegate类型的委托");
            });
        });

  // 上述中间件的定义代码可根据lamda表达式规则进行缩写
   Func<RequestDelegate, RequestDelegate> middleware = new Func<RequestDelegate, RequestDelegate>((RequestDelegate requestdelegate) =>
        {
            return new RequestDelegate(async (context) =>
            {
                await context.Response.WriteAsync("接收1个带RequestDelegate类型的参数,返回RequestDelegate类型的委托");
            });
        });

   Func<RequestDelegate, RequestDelegate> middleware = (request=>{
        return new RequestDelegate(async (context) =>
            {
                await context.Response.WriteAsync("接收1个带RequestDelegate类型的参数,返回RequestDelegate类型的委托");
            });
   });

3.1Use 方法配置中间件
//增加中间件到请求管道中
IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);

Use 扩展可以使用两个重载:
一个重载采用 HttpContext 和 Func < Task >。 不使用任何参数调用 Func< Task >。

     app.Use(async (context, next) =>
     {
        await context.Response.WriteAsync(" Rquest The first middleware");
        //调用下一个中间件
        await next.Invoke();
        await context.Response.WriteAsync(" Response The first middleware");
    });

另一个重载采用 HttpContext 和 RequestDelegate。 通过传递 HttpContext 调用 RequestDelegate。
优先使用后面的重载,因为它省去了使用其他重载时所需的两个内部每请求分配。

    app.Use(next =>
      {
          return new RequestDelegate(async context =>
          {
             await context.Response.WriteAsync(" Rquest The first middleware");
             await next.Invoke(context);
             await context.Response.WriteAsync(" Response The first middleware");
           });
      }
   );

上面两种方法实现的功能一致。值得注意的是,next参数表示管道中的下一个中间件。通过不调用下一个中间件,会导致请求短路或中断,所以需要谨慎的选择是否需要调用下一个中间件。

3.2Run 方法配置中间件
   public static void Run(this IApplicationBuilder app, RequestDelegate handler);

Run 方法配置请求管道时,会使得请求管道短路,因为它不调用下一个请求。因此Run方法一般只在管道的底部使用。


  app.Run( async context=> {
        await context.Response.WriteAsync(" Rquest The final middleware");
  });
3.2Map 方法配置中间件
//pathMatch 请求路径匹配字符串
//configuration 符合匹配规则时采取的 请求处理逻辑.
//configuration 是一个无返回,请求参数类型为 IApplicationBuilder的回调函数。
public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action<IApplicationBuilder> configuration);

Map 方法是一种可以基于请求路径的不同来配置分支中间件。

 app.Map("/secondturl", appBuilder => {
   appBuilder.Run(async context =>
    {
         await context.Response.WriteAsync(" the request'url is  secondturl" + "\n");
         });
    });

且可以在嵌套使用Map方法去配置分支中间件

4 自定义中间件

虽然中间件的本质是一个Func<RequestDelegate, RequestDelegate> middleware 对象,
中间件的类型可分为两种,下面自定义实现以及记录请求IP地址的中间件

  • 弱类型中间件
    (1) 定义Ip中间件
   public class RequestIpMiddleware
    {
        private readonly RequestDelegate requestDelegate;

        public RequestIpMiddleware(RequestDelegate requestDelegate) {
            this.requestDelegate = requestDelegate;
        }


        public async Task Invoke(HttpContext context) {

            context.Response.WriteAsync("The Request Ip is " + context.Request.HttpContext.Connection.RemoteIpAddress.ToString()+"\n");
            //调用下一个请求中间件
            await requestDelegate.Invoke(context);
        }
    }

(2)增加Use的拓展方法

    /// <summary>
    /// 调用中间件的扩展方法
    /// </summary>
    public static class MiddlewareExtensions
    {
        /// <summary>
        ///this 关键字不能省略
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseIpMiddleware( this IApplicationBuilder app ) 
        {
           return  app.UseMiddleware<RequestIpMiddleware>();
        }
    }

(3)Configure方法中使用该中间件

     app.UseIpMiddleware();
  • 强类型中间件

可以在Use方法中调用这个匿名内部类,但是最好是将中间件定义成一个强类型,利于阅读,且符合编程习惯。
IApplicationBuilder 提供了一种拓展方法来配置强类型的中间件

public static IApplicationBuilder UseMiddleware<TMiddleware>(this IApplicationBuilder app, params object[] args);

    /// <summary>
    /// 自定义中间件 
    /// </summary>
    public class IPMiddleware : IMiddleware
    {

        /// <summary>
        /// IMiddleware接口定义了唯一的InvokeAsync方法,用来实现对请求的处理。
        /// </summary>
        /// <param name="context"> 当前请求上下文</param>
        /// <param name="next">下一个请求requestDelegate</param>
        /// <returns></returns>
        public Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            //获取请求的IP
            var ip = context.Request.HttpContext.Connection.RemoteIpAddress.ToString();

            context.Response.WriteAsync("IP is "+ip+"\n");

            //调用下一个中间件
            return  next.Invoke(context);
        }
    }

值得注意的是在使用这个中间件时,需要将当前中间件注入到容器中,否则请求管道中的这个中间件无法生效。

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

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

相关文章

第一行代码 第七章 内容提供器

第七章 内容提供器 在上一章中我们学了Android数据持久化的技术&#xff0c;包括文件存储、SharedPreferences存储以及数据库存储。使用这些持久化技术所保存的数据都只能在当前应用程序中访问。 虽然文件和SharedPreferences存储中提供了MODE_WORLD_READABLE和MODE_WORLD_WR…

UU跑腿“跑男失联”:同城即配服务赛道商业逆袭难?

五一假期&#xff0c;人们纷纷走出家门&#xff0c;要么扎堆奔向“远方”&#xff0c;要么、享受本地烟火气息。 据文化和旅游部数据中心测算&#xff0c;劳动节假期&#xff0c;全国国内旅游出游合计2.74亿人次&#xff0c;同比增长70.83%。 五一假日的郑州东站 面对人山人海…

树莓派(主)与STM32(从)使用SPI通信

1.实验目的 2.SPI 简介 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是Motorola公司提出的一种同步串行数据传输标准 2.1 接口 SPI接口经常被称为4线串行总线&#xff0c;以主/从方式工作&#xff0c;数据传输过程由主机初始化。如图1…

【干货集】PCBA板边器件布局重要性

电子元器件在PCB板上的合理布局&#xff0c;是减少焊接缺点的极重要一环&#xff01;元器件要尽可能避开挠度值非常大的区域和高内应力区&#xff0c;布局应尽量匀称。 为了最大程度的利用电路板空间&#xff0c;相信很多做设计的小伙伴&#xff0c;会尽可能把元器件靠板的边缘…

机器学习基础知识之数据归一化

文章目录 归一化的原因1、最大最小归一化2、Z-score标准化3、不同方法的应用 归一化的原因 在进行机器学习训练时&#xff0c;通常一个数据集中包含多个不同的特征&#xff0c;例如在土壤重金属数据集中&#xff0c;每一个样本代表一个采样点&#xff0c;其包含的特征有经度、…

《程序员面试金典(第6版)》面试题 16.16. 部分排序(double双指针(多指针),C++)

题目描述 给定一个整数数组&#xff0c;编写一个函数&#xff0c;找出索引m和n&#xff0c;只要将索引区间[m,n]的元素排好序&#xff0c;整个数组就是有序的。注意&#xff1a;n-m尽量最小&#xff0c;也就是说&#xff0c;找出符合条件的最短序列。函数返回值为[m,n]&#xf…

什么是平台工程?如何开始?

平台工程是为开发人员构建和维护自助服务平台的学科。该平台提供了一套云原生工具和服务&#xff0c;帮助开发者快速高效地交付应用。平台工程的目标是通过标准化和自动化软件交付生命周期 (SDLC) 中的大部分任务来改善开发人员体验 (DX)。开发人员可以专注于使用自动化平台编码…

Type-C PD充电器诱骗PD+QC+AFC+FCP全协议快充取电5V9V12V15V20V

Type-C充电器采用的是PD快充协议&#xff0c;支持的电压高&#xff0c;电流大&#xff0c;一般有5V3A、9V3A、12V3A、15V3A、20V5A等等。 因为充电器内部有协议芯片&#xff0c;当外部设备连接时&#xff0c;设备会和充电器进行协议匹配&#xff0c;匹配成功之后&#xff0c;充…

ASEMI代理ADI亚德诺LT8609AJDDM#WTRPBF车规级芯片

编辑-Z LT8609AJDDM#WTRPBF特点&#xff1a; 宽输入电压范围&#xff1a;3.0V 至 42V 超低静态电流突发模式操作&#xff1a; 将 12VIN 调节到 3.3VOUT 时 IQ 为 2.5A 输出纹波 < 10mVP-P 高效 2MHz 同步操作&#xff1a; 1A 时效率为 93%, 12VIN 可获得 5VOUT 最大…

3.1 一个稍微完善的Vue.js响应式系统

前文提要&#xff1a;3.0 响应式系统的设计与实现 1、设置一个合理的effect副作用函数 如上文所说&#xff0c;如果我们直接将简单的effect函数作为副作用函数&#xff0c;如果一个副作用函数不叫effect岂不是找不到了。解决方案也很简单&#xff0c;我们设定一个全局变量用于…

在CRA中配置别名路径并添加别名路径提示

写在前面&#xff1a; 使用React官方脚手架create-react-app[简称CRA]创建react项目&#xff1a;npx create-react-app 项目名称 一、配置别名路径 1.1 写在前面 目的&#xff1a;简化项目中的路径处理&#xff0c;和Vue项目中的类似。 参考文档&#xff1a;自定义CRA的默认…

MySQL基础(十二)数据类型精讲

1. MySQL中的数据类型 类型类型举例整数类型TINYINT、SMALLINT、MEDIUMINT、INT(或INTEGER)、BIGINT浮点类型FLOAT、DOUBLE定点数类型DECIMAL位类型BIT日期时间类型YEAR、TIME、DATE、DATETIME、TIMESTAMP文本字符串类型CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT枚…

一个日期类深度认识operator符号重载

一&#xff1a;概念 在以前的C语言的学习中,如果我们需要比较两个整数并返回它的结果可以直接用与之相关的符号。例如我们可以直接写成A>B或者A<B一类的&#xff0c;但是它的局限性很大&#xff0c;只能比较内置类型&#xff0c;因为计算可以直接转换成对应的汇编代码进…

如何通过国外主机租用服务提高网站SEO排名?

当今的互联网已经成为了商业和社交活动的主要场所之一。在这个快速变化的数字时代&#xff0c;网站的搜索引擎优化(SEO)排名对于任何企业的成功都至关重要。一个好的SEO排名能够帮助企业吸引更多的访客和潜在客户&#xff0c;增加业务的转化率。而国外主机租用服务可以帮助您优…

【C++学习】函数模板

模板的概念 模板就是建立通用的模具&#xff0c;大大提高复用性。 模板的特点&#xff1a; 模板不可以直接使用&#xff0c;它只是一个模型 模板的通用不是万能的 基本语法 C中提供两种模板机制&#xff1a;函数模板和类模板 函数模板作用&#xff1a; 建立一个通用函数&…

C++学习day--05 C++数据类型

1、项目需求&#xff1a;实现黑客攻击系统菜单打印 实现&#xff1a; #include <iostream> #include <Windows.h> int main( void ) { std::cout << "1. 网站 404 攻击 " << std::endl; std::cout << "2. 网站篡改攻击 …

实验四 基于PPTP的远程VPN实现【网络安全】

实验四 基于PPTP的远程VPN实现【网络安全】 前言推荐实验四 基于PPTP的远程VPN实现使用&#xff1a;配置CentOS PPTP服务端配置CentOS PPTP客户端常见问题浏览器无法打开网页 最后 前言 2023-5-7 23:10:12 以下内容源自《【网络安全】》 仅供学习交流使用 推荐 第27节 远程…

TCP三次握手/四次挥手

TCP三次握手/四次挥手 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手 任何基于TCP的应用&#xff0c;在发送数据之前&#xff0c;都需要由TCP进行三次握手进行连接 握手流程&#xff1a; 三次握手原理 第1次握手&#xff1a;客户端发送一个带有SYN&#…

【蓝桥杯国赛真题26】Scratch队列练习 少儿编程scratch图形化编程 蓝桥杯省赛真题讲解

目录 scratch队列练习 一、题目要求 编程实现 二、案例分析 1、角色分析

2018年下半年软件设计师下午试题

试题四&#xff08;15分&#xff09; 给定一个字符序列Bb1b2….bn&#xff0c;其中bi∈{A,C,G,U}。B上的二级结构是一组字符对集合S{(bi,bj)},其中i,j∈{1,2,….,n}&#xff0c;并满足以下四个条件&#xff1a; &#xff08;1&#xff09;S中的每对字符是(A,U),(U,A),(C,G)和…