ASP.NET Core实现中间件的几种方式

前言

ASP.NET Core 中 HTTP 管道使用中间件组合处理的方式,

换句人话来说,

对于写代码的人而言,一切皆中间件.

业务逻辑/数据访问/等等一切都需要以中间件的方式来呈现.

那么我们必须学会如何实现自定义中间件 这里划重点,必考

这里我们介绍下中间件的几种实现方式...

匿名函数

通常新建一个空的 ASP.NET Core Web Application,项目名字无所谓啦

在启动类里可以看到这么一句:

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

这就是一个匿名函数实现的中间件,虽然内容比较少.

可以看到通过匿名函数实现的中间件是内嵌在启动类文件中的,因此通常也叫做内联中间件

接下来,我们通过匿名函数来实现内联中间件,以便加深理解.

然后修改启动类代码如下:

// Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace WebApplication1
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // 使用匿名函数实现一个内联中间件
            app.Use(async (context, next) =>
            {
                throw new NotImplementedException("一个使用匿名函数,但未实现具体内容的内联中间件");
            });

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

这里我们在 app.Run 之前使用 app.Use 添加一个匿名函数实现的内联中间件,按照中间件的注册顺序,当发起请求时,会抛出一个异常 NotImplementedException("一个使用匿名函数,但未实现具体内容的内联中间件")

我们 F5 启动下,看看页面

嗯,符合预期.

我们再来调整下启动类,代码如下:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication1
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // 使用匿名函数实现一个内联中间件
            app.Use(async (context, next) =>
            {
                // 这里不对 request 做任何处理,直接调用下一个中间件
                await next.Invoke();
            });

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

这里我们在 app.Run 之前使用 app.Use 添加一个匿名函数实现的内联中间件,该中间件没有对 request 做任何处理,只是一个空的空间件,按照中间件的注册顺序,当发起请求时,页面应该显示 Hello World!.

我们 F5 启动,看看效果

嗯,符合预期.

个人觉得:匿名函数不是很直观,但是用内联的方式可以快速开始一些开发,不用新建一个中间件类,不用专门想个不一样的名字,小场景下是非常方便实用的

实现接口

通过实现接口 IMiddleware 编写自定义中间件,这是一种强类型的方式,我们需要必须强制按照接口的定义来实现.

IMiddleware

接口 IMiddleware 定义如下:

using System.Threading.Tasks;

namespace Microsoft.AspNetCore.Http
{
    public interface IMiddleware
    {
        Task InvokeAsync(HttpContext context, RequestDelegate next);
    }
}

可以看到接口 IMiddleware 的命名空间是 Microsoft.AspNetCore.Http,需要实现的方法是InvokeAsync(),看起来不算太复杂, 嗯,看起来不算太复杂

嗯,重新开始,我们新建一个空的 ASP.NET Core Web Application

然后我们通过实现接口的方式来自定义一个中间件,代码如下:

// 新建类 MyMiddleware.cs
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class MyMiddleware : IMiddleware
    {
        public Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            throw new NotImplementedException();
        }
    }
}

按照上面实现的中间件 MyMiddleware,在执行时应该会抛出 NotImplementedException.

使用接口实现的中间件需要在先在服务容器中注册

// Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication1
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            // 在服务容器中注册自定义中间件
            services.AddSingleton<MyMiddleware>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // 使用 UseMiddleware() 把自定义中间件添加到管道中
            app.UseMiddleware<MyMiddleware>();

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

然后 F5 启动,页面上可以看到如下结果:

符合我们上面的预期,抛出了一个 NotImplementedException.

然后我们改造下 MyMiddleware 中间件

// MyMiddleware.cs
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class MyMiddleware : IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            // 这里不对 request 做任何处理,直接调用下一个中间件
            await next(context);
        }
    }
}

这里相当于我们实现了一个叫做 MyMiddleware 的中间件,但是并没有对请求进行任何处理,页面上应该正常显示 Hello World! 字符串.

然后我们 F5 启动看看

嗯...符合预期.

个人觉得:这种方式最符合面向对象的特性,也符合面向接口的原则,少一些难以理解的魔法,反而有助于理解.

约定方式

编程世界有这么一句话,叫"约定大于配置".

那么编写中间件的约定是什么呢?

重新开始,新建一个空的 ASP.NET Core Web Application

然后新建一个类,类名叫做 MyMiddleware 好了,代码如下:

// MyMiddleware.cs
using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class MyMiddleware
    {
        // 1. 需要实现一个构造函数,参数为 RequestDelegate
        public MyMiddleware(RequestDelegate next)
        {

        }

        // 2. 需要实现一个叫做 InvokeAsync 方法
        public async Task InvokeAsync(HttpContext context)
        {
            throw new NotImplementedException("这是一个按照约定方式编写的中间件,但未实现具体内容");
        }
    }
}

约定的内容,就是满足2个需要...不满足需要则异常.

然后我们把这个中间件,注册到管道中,以便使用

// Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication1
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // 注册自定义中间件
            // 注册顺序=1
            app.UseMiddleware<MyMiddleware>();

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

然后 F5 启动,来看看效果

嗯,符合预期.

然后我们来调整下中间件,让请求能正常响应输出 Hello World!

using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class MyMiddleware
    {
        private readonly RequestDelegate _next;

        // 需要实现一个构造函数,参数为 RequestDelegate
        public MyMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        // 需要实现一个叫做 InvokeAsync 方法
        public async Task InvokeAsync(HttpContext context)
        {
            // 不处理任何 request, 直接调用下一个中间件
            await _next.Invoke(context);
        }
    }
}

然后 F5 启动,看看效果

嗯,符合预期.

个人觉得:只能说一句,约定方式是目前用的最多的方式...

End

写在最后

Tips: 有些内容可能看起来还是不太容易理解,至少当下你是很难理解的,但是套路就在哪里,好比1+1=2,你知道1+1为什么=2么?但你一定会算会用1+1=2...

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • ASP.NET Core自定义中间件的方式详解

    目录 1.委托形式 2.强类型中间件 2.1.定义中间件的依赖 2.2.定义中间件类型 3.基于约定的中间件 3.1.约定规则 3.2.应用实现 总结 ASP.NET Core应用本质上,其实就是由若干个中间件构建成的请求处理管道.管道相当于一个故事的框架,而中间件就相当于故事中的某些情节.同一个故事框架采用不同的情节拼凑,最终会体现出不同风格的故事.而我们的ASP.NET Core应用也正是如此,同一管道采用不同的中间件组合,最终也会呈现出不同的应用形态. 从上述的概念种可以看出,中间件在AS

  • ASP.NET Core使用自定义日志中间件

    这个日志框架使用的是ASP.NET Core的NLog,用来记录每次请求信息和返回信息. 1.首先创建一个Web应用项目,我选择的是MVC模板: 2.使用NuGet添加Microsoft.Extensions.Logging和NLog.Extensions.Logging 3.修改Configure方法: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFac

  • ASP.NET Core基础之中间件

    什么是ASP.NET Core Middleware? ASP.NET Core中间件组件是被组装到应用程序管道中以处理HTTP请求和响应的软件组件(从技术上来说,组件只是C#类). ASP.NET Core应用程序中的每个中间件组件都执行以下任务. 选择是否将 HTTP 请求传递给管道中的下一个组件.这可以通过在中间件中调用下一个 next() 方法实现. 可以在管道中的下一个组件之前和之后执行工作. 在ASP.NET Core中,已经有很多内置的中间件组件可供使用,您可以直接使用它们. 如果

  • ASP.NET Core中间件用法与官方常用中间件介绍

    目录 一.什么是中间件 中间件和过滤器的区别 二.中间件常用方法 1.Run方法 2.Use方法 3.Map方法 4.Mapwhen方法 三.自定义中间件 四.官方常用中间件 1.异常处理中间件 2.HTTPS重定向中间件 3.静态文件中间件 4.Cookie中间件 5.路由中间件 6.身份认证中间件 7.授权中间件 8.会话中间件 9.终结点路由中间件 一.什么是中间件 我们都知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终才会到达我们写的

  • ASP.NET Core基础之异常中间件

    了解异常中间件 首先,使用ASP.NET模板创建一个核心应用程序.默认情况下,ASP.NET核心应用程序只是返回应用程序未处理的异常的状态代码.如下所示,我们引发异常. 运行应用程序时,将得到以下输出. 如上图所示,它为您提供的状态代码为 500,这意味着内部服务器错误.但是,作为开发人员,在开发应用程序时,您应该知道有关页面上异常的详细信息,以便可以采取必要的操作来修复错误. 如何使用异常中间件? 如果希望应用程序显示显示有关未处理异常的详细信息的页面,则需要在请求处理管道中配置开发人员异常页

  • ASP.NET Core中间件实现限流的代码

    目录 一.限流算法 1.计数器算法 1.1固定窗口算法 1.2滑动窗口算法 2.令牌桶算法 3.漏桶算法 二.ASP.NETCore中间件实现限流 1.中间件代码 2.在管道中的使用 一.限流算法 在高并发系统中,有三把利器用来保护系统:缓存.降级和限流. 本文主要是介绍限流,限流算法主要有以下三种: 1.计数器算法 固定窗口 滑动窗口 2.令牌桶算法 3.漏桶算法 1.计数器算法 1.1 固定窗口算法 计数器算法是限流算法里最简单也是最容易实现的一种算法.比如我们规定,对于A接口来说,我们1分

  • ASP.NET Core中间件

    目录 1.前言 2.使用中间件 2.1 Run 2.2 Use 2.3 Map和MapWhen 3.顺序 4.编写中间件(重点) 4.1中间件类 4.2中间件扩展方法 5.按每次请求创建依赖注入(DI) 1.前言 整个HTTP Request请求跟HTTP Response返回结果之间的处理流程是一个请求管道(request pipeline).而中间件(middleware)则是一种装配到请求管道以处理请求和响应的组件.每个组件: 可选择是否将请求传递到管道中的下一个组件. 可在管道中的下一个

  • ASP.NET Core的中间件与管道介绍

    今天来讨论一个ASP.NET Core 很重要概念管道和中间件,在ASP.NET Core中,针对HTTP请求采用pipeline也就是通常说的管道方式来处理,而管道容器内可以挂载很多中间件(处理逻辑)“串联”来处理HTTP请求,每一个中间件都有权决定是否需要执行下一个中间件,或者直接做出响应.这样的机制使得HTTP请求能够很好的被层层处理和控制,并且层次清晰处理起来甚是方便. 示意图如下: 为了再次说明管道和中间件的概念,举一个官方给出的权限验证的例子,中间件A,B分别按顺序挂载在管道容器中,

  • 详解ASP.NET Core中间件Middleware

    本文为官方文档译文,官方文档现已非机器翻译 https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1 什么是中间件(Middleware)? 中间件是组装到应用程序管道中以处理请求和响应的软件. 每个组件: 选择是否将请求传递给管道中的下一个组件. 可以在调用管道中的下一个组件之前和之后执行工作. 请求委托(Request delegates)用于构建请求管道,处理每个HTT

  • ASP.NET Core实现中间件的几种方式

    前言 ASP.NET Core 中 HTTP 管道使用中间件组合处理的方式, 换句人话来说, 对于写代码的人而言,一切皆中间件. 业务逻辑/数据访问/等等一切都需要以中间件的方式来呈现. 那么我们必须学会如何实现自定义中间件 这里划重点,必考 这里我们介绍下中间件的几种实现方式... 匿名函数 通常新建一个空的 ASP.NET Core Web Application,项目名字无所谓啦 在启动类里可以看到这么一句: // Startup.cs // ... app.Run(async (cont

  • 在 asp.net core 的中间件中返回具体的页面的实现方法

    前言 在 asp.net core 中,存在着中间件这一概念,在中间件中,我们可以比过滤器更早的介入到 http 请求管道,从而实现对每一次的 http 请求.响应做切面处理,从而实现一些特殊的功能 在使用中间件时,我们经常实现的是鉴权.请求日志记录.全局异常处理等等这种非业务性的需求,而如果你有在 asp.net core 中使用过 swashbuckle(swagger).health check.mini profiler 等等这样的组件的话,你会发现,这些第三方的组件往往都提供了页面,允

  • ASP.NET Core自定义中间件如何读取Request.Body与Response.Body的内容详解

    背景# 最近在徒手造轮子,编写一个ASP.NET Core的日志监控器,其中用到了自定义中间件读取Request.Body和Response.Body的内容,但是编写过程,并不像想象中的一帆风顺,ASP.NET Core针对Request.Body和Response.Body的几个特殊设计,导致了完成以上功能需要绕一些弯路. 原始代码# 为了读取Request.Body和Response.Body的内容,我的实现思路如下: 创建一个LoggerMiddleware的中间件,将它放置在项目中间件管

  • ASP.NET Core设置URLs的五种方法

    目录 前言 URL格式 前提条件 方法1 使用环境变量 方法2 使用命令行参数 方法3 使用配置文件 方法4 使用UseUrls 方法5 使用Kestrel 优先级 总结 前言 在使用ASP.NET Core 3.1开发时,需要配置服务器监听的端口和协议,官方帮助文档进行简单说明,文档中提到了4种指定URL的方法 设置ASPNETCORE_URLS 环境变量: 使用dotnet --urls 命令行参数: 使用urls作为键进行配置: 使用UseUrls扩展方法: 为便于讲清楚URLs设置方法,

  • ASP调用带参数存储过程的几种方式

    ASP调用带参数存储过程的几种方式     选择自 hxfwsk 的 Blog   关键字   存储过程  出处 作者: 讨饭猫 ASP调用带参数存储过程的几种方式 最近有很多的朋友问到调用存储过程的问题,这里简单介绍几种ASP调用带参数存储过程的方法. 1 这也是最简单的方法,两个输入参数,无返回值: set connection = server.createobject("adodb.connection") connection.open someDSN  Connection

  • ASP.NET Core应用错误处理之三种呈现错误页面的方式

    前言 由于ASP.NET Core应用是一个同时处理多个请求的服务器应用,所以在处理某个请求过程中抛出的异常并不会导致整个应用的终止.出于安全方面的考量,为了避免敏感信息的外泄,客户端在默认的情况下并不会得到详细的出错信息,这无疑会在开发环境下增加查错纠错的难度.对于生产环境来说,我们也希望最终用户能够根据具体的错误类型得到具有针对性并且友好的错误消息.ASP.NET Core提供了相应的中间件帮助我们将定制化的错误信息呈现出来,这些中间件都定义在"Microsoft.AspNetCore.Di

  • Asp.Net Core 通过中间件防止图片盗链的实例

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

  • 详解ASP.NET 页面之间传值的几种方式

    开篇概述 对于任何一个初学者来说,页面之间传值可谓是必经之路,却又是他们的难点.其实,对大部分高手来说,未必不是难点. 回想2016年面试的将近300人中,有实习生,有应届毕业生,有1-3年经验的,有3-5年经验的,有5-10年经验的,对于所有的面试者,我几乎问了同一道题:"请说说你所知道的页面之间传值的几种形式和方法,并阐述他们的原理和过程",关于这道题,从大家的回答来看,结果并不是很理想,从种类上来说,大部分人回答5种左右,极少部分能回答8种,没有超过8种的,但从深度上来说,很少有

随机推荐