aspnetcore中的中间件详解-kb88凯时官网登录

来自:网络
时间:2024-06-10
阅读:

1 什么叫做中间件?

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

aspnetcore中的中间件详解

其中关于请求管道配置的一个重要方法在startup中的configure(iapplicationbuilder app, iwebhostenvironment env)方法。可用use、map、run方法来配置需要使用的中间件。通常使用
iapplicationbuilder的拓展方法来配置请求管道,加入指定的中间件。

iapplicationbuilder use(func 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 请求短路与中间件顺序

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

aspnetcore中的中间件详解

3 中间件配置方法use、run、map

asp.net 中的核心请求管道是通过一个个请求委托串联而来的,具体是通过iapplicationbuilder的use、run、map方法来实现的。

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

    //一个能处理请求的方法
    public delegate task requestdelegate(httpcontext context);
   //中间件原生定义,委托,输入是一个requestdelegate,输出也是一个requestdelegate,
    func middleware = new func((requestdelegate requestdelegate) =>
        {
            return new requestdelegate(async (context) =>
            {
                await context.response.writeasync("接收1个带requestdelegate类型的参数,返回requestdelegate类型的委托");
            });
        });
  // 上述中间件的定义代码可根据lamda表达式规则进行缩写
   func middleware = new func((requestdelegate requestdelegate) =>
        {
            return new requestdelegate(async (context) =>
            {
                await context.response.writeasync("接收1个带requestdelegate类型的参数,返回requestdelegate类型的委托");
            });
        });
   func middleware = (request=>{
        return new requestdelegate(async (context) =>
            {
                await context.response.writeasync("接收1个带requestdelegate类型的参数,返回requestdelegate类型的委托");
            });
   });

3.1use 方法配置中间件

//增加中间件到请求管道中
iapplicationbuilder use(func 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 configuration);

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

 app.map("/secondturl", appbuilder => {
   appbuilder.run(async context =>
    {
         await context.response.writeasync(" the request'url is  secondturl"   "\n");
         });
    });

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

4 自定义中间件

虽然中间件的本质是一个func 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的拓展方法

    /// 
    /// 调用中间件的扩展方法
    /// 
    public static class middlewareextensions
    {
        /// 
        ///this 关键字不能省略
        /// 
        /// 
        /// 
        public static iapplicationbuilder useipmiddleware( this iapplicationbuilder app ) 
        {
           return  app.usemiddleware();
        }
    }

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

     app.useipmiddleware();

强类型中间件

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

public static iapplicationbuilder usemiddleware(this iapplicationbuilder app, params object[] args);
    /// 
    /// 自定义中间件 
    /// 
    public class ipmiddleware : imiddleware
    {
        /// 
        /// imiddleware接口定义了唯一的invokeasync方法,用来实现对请求的处理。
        /// 
        ///  当前请求上下文
        /// 下一个请求requestdelegate
        /// 
        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);
        }
    }

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

返回顶部
顶部
网站地图