asp.net core 系列 15 中间件

原文:asp.net core 系列 15 中间件

一.概述

  中间件(也叫中间件组件)是一种装配到应用管道以处理请求和响应的软件。 每个组件:(1)选择是否将请求传递到管道中的下一个组件;(2)可以在管道中的下一个组件之前和之后执行工作。

  请求委托用于生成请求管道。 请求委托会处理每个 HTTP 请求。使用以下方法配置请求委托:Run,  Map, Use扩展方法。可以将单个请求委托作为匿名方法(称为内联中间件in-line middleware) 或者可以在可重用类中定义。这些可重用的类和内联匿名方法是中间件,也称为中间件组件。请求管道中的每个中间件组件负责调用管道中的下一个组件,或使管道短路。

  (1) Run

      //将终端中间件委托添加到应用程序的请求管道中。
      public static class RunExtensions
      {
          public static void Run(this IApplicationBuilder app, RequestDelegate handler);
      }

   (2) Map

      // 根据给定请求路径的匹配对请求管道进行分支。
      public static class MapExtensions
      {
          public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action<IApplicationBuilder> configuration);
      }

  (3) Use

      // 提供配置应用程序请求的机制
      public interface IApplicationBuilder
      {
          //....
          // 将中间件委托添加到应用程序的请求管道中。
          IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
      }

  1.1 使用 IApplicationBuilder 创建中间件管道

    在Startup. Configure方法中,使用IApplicationBuilder来创建中间件管理。每一个use开头的扩展方法将一个中间件添加到IApplicationBuilder请求管道中。使用Use扩展方法来配置请求委托。每个use的中间件类似如下声明:

    public static IApplicationBuilder Use[Middleware] (this IApplicationBuilder app )
      public static IApplicationBuilder Use[Middleware] (this IApplicationBuilder app , Action<T>)

    ASP.NET Core 请求管道包含一系列请求委托,依次调用。 下图演示了这一概念。 沿黑色箭头执行。

  在Startup. Configure代码中,一系列use请求委托中间件如下所示:

           app.UseHttpsRedirection();
           app.UseStaticFiles();
           app.UseCookiePolicy();
           app.UseMvc();

    委托可以决定不将请求传递给下一个委托(中间件),这就是对请求管道进行短路。通常需要短路,因为这样可以避免不必要的工作。

    下面示例 是一个最简单的 ASP.NET core 应用程序,用run方法配置请求委托,设置单个委托处理处理所有请求。此案例不包括实际的请求管道。相反,调用单个匿名函数以响应每个 HTTP 请求。并用委托终止了管道。

    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello, World!");
            });
        }
    }

    下面示例用Use方法将多个请求委托链接在一起,next 参数表示管道中的下一个委托。 可通过不调用 next 参数使管道短路。

            app.Use(async (context, next) =>
            {
              //调用下一个委托(app.run)
                await next.Invoke();
            });

            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello, World!");
            });

    

  1.2 中间件顺序

    向 Startup.Configure 方法添加中间件组件的顺序定义了针对请求调用这些组件的顺序,以及响应的相反顺序。 此排序对于安全性、性能和功能至关重要。以下 Startup.Configure 方法将为常见应用方案添加中间件组件:  

   (1) 异常/错误处理

    (2) HTTP 严格传输安全协议

  (3) HTTPS 重定向

  (4) 静态文件服务器

     (5) Cookie 策略实施

  (6) 身份验证

  (7) 会话

    (8) MVC

public void Configure(IApplicationBuilder app)
{
    if (env.IsDevelopment())
    {
        // When the app runs in the Development environment:
        //   Use the Developer Exception Page to report app runtime errors.
        //   Use the Database Error Page to report database runtime errors.
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        // When the app doesn‘t run in the Development environment:
        //   Enable the Exception Handler Middleware to catch exceptions
        //     thrown in the following middlewares.
        //   Use the HTTP Strict Transport Security Protocol (HSTS)
        //     Middleware.
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    // Use HTTPS Redirection Middleware to redirect HTTP requests to HTTPS.
    app.UseHttpsRedirection();

    // Return static files and end the pipeline.
    app.UseStaticFiles();

    // Use Cookie Policy Middleware to conform to EU General Data
    // Protection Regulation (GDPR) regulations.
    app.UseCookiePolicy();

    // Authenticate before the user accesses secure resources.
    app.UseAuthentication();

    // If the app uses session state, call Session Middleware after Cookie
    // Policy Middleware and before MVC Middleware.
    app.UseSession();

    // Add MVC to the request pipeline.
    app.UseMvc();
}

    (1) UseExceptionHandler 是添加到管道的第一个中间件组件。 该异常处理程序中间件可捕获稍后调用中发生的任何异常。

    (2) UseStaticFiles 静态文件中间件,应该在管道的早期调用。这样它就可以处理请求和短路,而不需要遍历其余组件。静态文件中间件不提供授权检查。 它提供的任何文件,包括wwwroot下的文件,都是公开可访问的。

    (3) UseAuthentication 身份验证中间件。未经身份验证的请求不会短路,但只有在特定的Razor页面或MVC控制器操作之后,才会发生授权(和拒绝)。

  1.3  Use、Run 和 Map

    配置 HTTP 管道可以使用Use、Run 和 Map,但各方法针对构建的中间件作用不同:

      (1) Use[Middleware]中间件负责调用管道中的下一个中间件,也可使管道短路(即不调用 next 请求委托)。

      (2) Run[Middleware]是一种约定,一些中间件组件可能会公开在管道末端运行的Run[Middleware]方法。

      (3) Map扩展用作约定来创建管道分支, Map*创建请求管道分支是基于给定请求路径的匹配项。

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.Map("/Map1",HandleMapTest1);
            app.Map("/Map2", HandleMapTest2);
            //其它请求地址
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
            });
        }

        private static void HandleMapTest1(IApplicationBuilder app)
        {
             app.Run(async context =>
            {
                await context.Response.WriteAsync("Map Test 1");
            });
        }

        private static void HandleMapTest2(IApplicationBuilder app)
        {
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Map Test 2");
            });
        }

    Map  还支持嵌套,下面的示例中,请求访问/level1/level2a 和 /level1/level2b时进行不同逻辑处理:

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

    

  1.4 MapWhen

    MapWhen 基于url给定谓词的结果创建请求管道分支。 Func<HttpContext, bool> 类型的任何谓词均可用于将请求映射到管道的新分支。 在以下示例中,谓词用于检测查询字符串变量 branch 是否存在,如果存在使用新分支(HandleBranch)。

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //Func<HttpContext, bool> predicate, Action<IApplicationBuilder> configuration
            app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

            //非匹配branch其它请求地址
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
            });
        }

        private static void HandleBranch(IApplicationBuilder app)
        {
             app.Run(async context =>
            {
                var branchVer = context.Request.Query["branch"];
                await context.Response.WriteAsync("Map Test 1");
            });
        }

二. 编写中间件    

  上面演示在请求管道中使用use,map,run方法,来委托处理每个 HTTP 请求就是中间件。通常中间件会封装在类中,并且通过扩展方法公开。下面示例是如何编写一个中间件组件。处理逻辑是该中间件通过查询字符串设置当前请求的区域性。

    /// <summary>
    /// 自定义中间件实现类
    /// </summary>
    public class RequestCultureMiddleware
    {
        //using Microsoft.AspNetCore.Http
        private readonly RequestDelegate _next;
      

      /// <summary>
      /// 程序启动时调用
      /// </summary>
      /// <param name="next"></param>

    public RequestCultureMiddleware(RequestDelegate next)
        {
            this._next = next;
        }

    

      /// <summary>
      ///每个页面请求时自动调用,方法按约定命名,必需是Invoke或InvokeAsync
      /// </summary>
      /// <param name="context"></param>
      /// <returns></returns>

    public async Task InvokeAsync(HttpContext context)
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                //using System.Globalization;
                var culture = new CultureInfo(cultureQuery);

                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;

            }
            // Call the next delegate/middleware in the pipeline
            await _next(context);
        }
    }

    /// <summary>
    /// 通过扩展方法公开中间件
    /// </summary>
    public static class RequestCultureMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestCulture(this IApplicationBuilder builder)
        {
            //在管道中添加一个use的中间件
            return builder.UseMiddleware<RequestCultureMiddleware>();
        }
    }
        public void Configure(IApplicationBuilder app)
        {
            //调用中间件
            app.UseRequestCulture();

            app.Run(async (context) =>
            {
                await ResponseAsync(context);
            });

        }

        private  async  Task ResponseAsync(HttpContext context)
        {
            context.Response.ContentType = "text/html; charset=utf-8";
            await context.Response.WriteAsync(
                    //打印当前显示的语言
                    $"Hello { CultureInfo.CurrentCulture.DisplayName }"
                    );
        }

  2.1 请求依赖项

    由于中间件是在应用启动时构造的(实例),而不是在每个请求时的,因此在每个请求过程中,中间件构造函数使用的作用域生命周期服务,不会在每个请求期间与其他依赖注入类型共享。如果必须在中间件和其他类型之间共享一个范围服务,请将这些服务添加到 Invoke 方法的签名。 Invoke 方法可接受由 DI 填充的参数:

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

    public CustomMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // IMyScopedService is injected into Invoke
    public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
    {
        svc.MyProperty = 1000;
        await _next(httpContext);
    }
}

  参考文献:

    官方文档:ASP.NET Core 中间件

原文地址:https://www.cnblogs.com/lonelyxmas/p/10317477.html

时间: 2024-07-28 23:14:07

asp.net core 系列 15 中间件的相关文章

asp.net core 系列 16 Web主机 IWebHostBuilder

原文:asp.net core 系列 16 Web主机 IWebHostBuilder 一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适用于托管 Web 应用:通用主机(ASP.NET Core 2.1 或更高版本)是适用于托管非 Web 应用:在未来的版本中,通用主机将适用于托管任何类型的应用,包括 Web 应用. 通用主机最终将取代 Web

asp.net core 系列 14 错误处理

一.概述 本文介绍处理 ASP.NET Core 应用中常见错误的一些方法.主要是关于:开发环境异常页:非开发环境配置自定义异常处理页:配置状态代码页(没有正文响应,http状态400~599的). 1.1 开发环境异常页 要将应用配置为显示有关异常的详细信息的页面,请使用开发环境异常页.要环境设置为 Development,具体查看:asp.net core系列9环境.下面向 Startup.Configure 方法添加代码行: if (env.IsDevelopment()) { //注意:

asp.net core系列 64 结合eShopOnWeb全面认识领域模型架构

原文:asp.net core系列 64 结合eShopOnWeb全面认识领域模型架构 一.项目分析 在上篇中介绍了什么是"干净架构",DDD符合了这种干净架构的特点,重点描述了DDD架构遵循的依赖倒置原则,使软件达到了低藕合.eShopOnWeb项目是学习DDD领域模型架构的一个很好案例,本篇继续分析该项目各层的职责功能,主要掌握ApplicationCore领域层内部的术语.成员职责. 1. web层介绍 eShopOnWeb项目与Equinox项目,双方在表现层方面对比,没有太大

Asp.Net Core 通过自定义中间件防止图片盗链的实例(转)

一.原理 要实现防盗链,我们就必须先理解盗链的实现原理,提到防盗链的实现原理就不得不从HTTP协议说起,在HTTP协议中,有一个表头字段叫referer,采用URL的格式来表示从哪儿链接到当前的网页或文件.换句话说,通过referer,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示它的网页地址.有了referer跟踪来源就好办了,这时就可以通过技术手段来进行处理,一旦检测到来源不是本站即进行阻止或者返回指定的页面.如果想对自己的网站进行防盗链保护,则需要针对不同的情况进行区

ASP.NET CORE系列【五】webapi整理以及RESTful风格化

原文:ASP.NET CORE系列[五]webapi整理以及RESTful风格化 介绍 什么是RESTful?  这里不多做赘述,详情请百度! 哈哈,本来还想巴拉巴拉介绍一些webapi, RESTful的, 还是算了,咱们直接上干货!(原因是懒!哈哈) 使用 以前使用过mvc的人对webapi 应该都很熟悉,先看一段熟悉的代码 大伙发现了什么没?跟以往mvc大多数相同,但有些地方不同 ,我们来一起看看有何区别 1.首先SysUsersController上面有一段代码 [Produces("a

ASP.NET CORE系列【一】搭建ASP.NET CORE项目

原文:ASP.NET CORE系列[一]搭建ASP.NET CORE项目 为什么要使用 ASP.NET Core? NET Core 刚发布的时候根据介绍就有点心里痒痒,微软的尿性都懂的,新东西bug太多,现在2.0也发布很久了,决定研究一下. ASP.NET Core官方文档https://docs.microsoft.com/en-us/aspnet/core/getting-started ASP.NET Core 具有如下优点: 生成 Web UI 和 Web API 的统一场景. 集成

ASP.NET CORE系列【二】使用Entity Framework Core进行增删改查

原文:ASP.NET CORE系列[二]使用Entity Framework Core进行增删改查 介绍 EntityFrameworkCore EF core 是一个轻量级的,可扩展的EF的跨平台版本.对于EF而言 EF core 包含许多提升和新特性,同时 EF core 是一个全新的代码库,并不如 EF6 那么成熟和稳定.EF core 保持了和EF相似的开发体验,大多数顶级API都被保留了下来,所以,如果你用过EF6,那么上手EF core你会觉得非常轻松和熟悉,EF core 构建在一

1.1专题介绍「深入浅出ASP.NET Core系列」

大家好,我是架构师张飞洪,专注于.NET平台十年有余. 工作之余喜欢阅读和写作,学习的内容包括数据结构/算法.网络技术.Linux系统原理.数据库技术原理,设计模式.前沿架构.微服务.容器技术等等…… 喜欢但不限于,Java.C.C++.Python.Javascript……Wait……不装了,因为我也还在学习的路上,愿你我一起终生学习. 定调 这里先给整个文章的系列定一个调调,起名深入浅出ASP.NET Core系列.深入的目的是希望能了解底层机制,浅出是为了学习能不让自己那么枯燥,给自己定个

目录导航「深入浅出ASP.NET Core系列」

希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. 入门篇 1.1课程介绍「深入浅出ASP.NET Core系列」 1.2环境安装「深入浅出ASP.NET Core系列」 1.3创建项目「深入浅出ASP.NET Core系列」 1.4部署到IIS「深入浅出ASP.NET Core系列」 1.5准备CentOS和Nginx环境「深入浅出ASP.NET Core系列」 1.6部署到CentOS「深入浅出ASP.NET Core系列」 2.1命令行和JSON的配置「深