ASP.NET 6 中间件系列 - 自定义中间件类

5302fc34d2334152e59af53ac97aa93e.png

这篇文章是 ASP.NET 6 中间件系列文章的第2部分,点击这里可以阅读第1部分。

在上一篇文章中,我们讨论了什么是中间件,它的作用是什么,以及在 ASP.NET 6 应用管道中添加中间件的简单方法。

在这篇文章中,我们将在这些基础上来扩展构建一些自定义中间件类。

示例项目

在 GitHub 上可以获得这篇文章涉及到的代码:

https://github.com/zilor-net/ASPNET6Middleware/tree/Part2

标准中间件结构

与我们在第1部分中所做的不同,大多数时候我们希望中间件是独立的类,而不是在 Program.cs 文件中创建。

让我们回顾一下第1部分的内容,一个响应“Hello Dear Readers!”内容的中间件?

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

接下来,让我们创建一个自定义中间件类来实现同样的效果。

中间件类的基础知识

下面是一个空类,我们将用于这个中间件:

namespace ASPNET6Middleware.Middleware
{public class SimpleResponseMiddleware{}
}

中间件类由三部分组成:

首先,任何中间件类都必须拥有RequestDelegate类型的私有成员实例,该实例由类的构造函数填充。

RequestDelegate代表管道中的下一个中间件:

namespace ASPNET6Middleware.Middleware
{private readonly RequestDelegate _next;public SimpleResponseMiddleware(RequestDelegate next){_next = next;}
}

其次,这个类必须有一个async方法InvokeAsync(),它接受一个HttpContext类型的实例作为它的第一个参数:

public class SimpleResponseMiddleware
{private readonly RequestDelegate _next;public SimpleResponseMiddleware(RequestDelegate next){_next = next;}public async Task InvokeAsync(HttpContext context){//...Implementation}
}

第三,中间件必须有自己的实现。对于这个中间件,我们要做的就是返回一个自定义的响应:

public class SimpleResponseMiddleware
{private readonly RequestDelegate _next;public SimpleResponseMiddleware(RequestDelegate next){_next = next;}public async Task InvokeAsync(HttpContext context){await context.Response.WriteAsync("Hello Dear Readers!");}
}

注意:在InvokeAsync()方法中,大多数中间件都会调用await next(context);,任何不这样做的中间件都会是一个终端中间件,它代表着管道的终结,它之后的中间件都不会执行。

向管道中添加中间件

此时,我们可以使用UseMiddleware<>()方法,将这个中间件类添加到 Program.cs 文件中的 app 中:

app.UseMiddleware<LayoutMiddleware>();

对于简单的中间件类,这就足够了。

然而,我们更加常用的方式是使用扩展方法,而不是直接使用UseMiddleware<>(),因为这可以为我们提供一层更加具体的封装:

namespace ASPNET6Middleware.Extensions
{public static class MiddlewareExtensions{public static IApplicationBuilder UseSimpleResponseMiddleware(this IApplicationBuilder builder){return builder.UseMiddleware<SimpleResponseMiddleware>();}}
}

然后我们可以像这样使用这个扩展方法:

app.UseSimpleResponseMiddleware();

这两种方法都是正确的,但是我个人更喜欢扩展方法的清晰性和可读性。

构建日志中间件

在第1部分时就介绍过,中间件最常见的场景之一是日志记录,特别是记录请求路径或响应头、响应体等内容。

LoggingService 类

我们将构建一个日志中间件类,它只做两件事:

  1. 记录请求路径。

  2. 记录唯一响应头。

首先,我们必须创建接口ILoggingService和类LoggingService

namespace ASPNET6Middleware.Logging
{public class LoggingService : ILoggingService{public void Log(LogLevel logLevel, string message){// 日志具体实现省略}}public interface ILoggingService{public void Log(LogLevel level, string message);}
}

然后我们需要在 Program.cs 中将LoggingService添加到应用程序的Services集合中:

var builder = WebApplication.CreateBuilder(args);builder.Services.AddRazorPages();
builder.Services.AddTransient<ILoggingService, LoggingService>();

中间件类也像普通类一样可以注入服务。

LoggingMiddleware 类

现在我们需要一个LoggingMiddleware类来做日志。

首先,让我们为LoggingMiddleware类创建好中间件结构,它在构造函数中接受一个ILoggingService的实例作为参数:

namespace ASPNET6Middleware.Middleware
{public class LoggingMiddleware{private readonly RequestDelegate _next;private readonly ILoggingService _logger;public LoggingMiddleware(RequestDelegate next, ILoggingService logger){_next = next;_logger = logger;}public async Task InvokeAsync(HttpContext context){//...}}
}

我们的任务是记录请求的路径和响应的唯一头,这意味着在await next(context)的前后都有代码:

namespace ASPNET6Middleware.Middleware
{public class LoggingMiddleware{//..public async Task InvokeAsync(HttpContext context){// 记录传入的请求路径_logger.Log(LogLevel.Information, context.Request.Path);// 调用管道中的下一个中间件await _next(context);// 获得唯一响应头var uniqueResponseHeaders = context.Response.Headers.Select(x => x.Key).Distinct();// 记录响应头名称_logger.Log(LogLevel.Information, string.Join(", ", uniqueResponseHeaders));}}
}

将 LoggingMiddleware 添加到管道中

因为我更喜欢使用扩展方法来添加中间件到管道中,让我们创建一个新的扩展方法:

namespace ASPNET6Middleware.Extensions
{public static class MiddlewareExtensions{//...public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder){return builder.UseMiddleware<LoggingMiddleware>();}}
}

最后,我们需要在 Program.cs 中调用我们的新扩展方法,将LoggingMiddleware类添加到管道中:

app.UseLoggingMiddleware();

当我们运行应用程序时,我们可以看到代码(通过断点)可以正确地记录请求路径和响应头。

0cbd089eec73873fefa8dea4fd2944b7.png

在本系列的下一篇文章中,我们将讲述中间件的执行顺序,展示一个记录执行时间的新中间件,并讨论在创建中间件管道时可能发生的一些常见问题。

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

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

相关文章

如何在IE浏览器里面定位到关键字的位置(页面代码)和这个关键字位置模块的请求

1 问题 比如用IE浏览器,打开一个页面,如何定位到关键字的具体位置,以及这个位置请求是什么?可能这个请求不是主页面的请求,因为我们知道页面html里面可以嵌套很多Frame(框架),把页面分割成很多块,然而每个Frame(框架)里面可以再嵌套一个url,有时候我们需要找到这个请求…

Java并发编程-原子性变量

image.png1. 原子性布尔 AtomicBoolean AtomicBoolean 类为我们提供了一个可以用原子方式进行读和写的布尔值&#xff0c;它还拥有一些先进的原子性操作&#xff0c;比如 compareAndSet()。AtomicBoolean 类位于 java.util.concurrent.atomic 包&#xff0c;完整类名是为 java.…

【C语言简单说】八:分支结构之if...else...(2)

上一节我们说了if的基本用法&#xff0c;这一小节我们来说明if…else…的用法 首先惯例举例子&#xff1a; 你今天早上饿了&#xff0c;打算去吃包子&#xff0c;可是没有包子了&#xff0c;你打算去吃米粉。 你昨天早上下雨了&#xff0c;带伞出门&#xff0c;结果没找到&a…

Java集合之LinkedList

上一篇写的是ArrayList&#xff0c;这一篇写一下LinkedList. 开宗明义&#xff0c;因为Vector已经被废弃了&#xff0c;所以list家族只剩下ArrayList和LinkedList两兄弟了&#xff0c;这里直接对比一下二位&#xff1a; ArrayList基于动态数组的实现&#xff0c;它长于随机访问…

由于开发者通过接口修改了菜单配置_Android SDK开发艺术探索(四)个性化配置...

一、前言本篇是Android SDK开发艺术探索系列的第四篇文章。介绍了通过流式API设计思想优雅地实现SDK的自定义选项配置需求。目录概览&#xff1a;一、前言 二、SDK自定义配置2.1、什么是自定义配置2.2、设计一个配置方法 三、结语系列文章&#xff1a;Android SDK开发艺术探索&…

C#中切片语法糖的使用

例子首先我们看这样一个例子&#xff0c;有这样一个数组string [] lst new string[] { "1", "2", "3", "4", "5", "6", "7" };我们怎么获取它的最后一个值&#xff0c; 传统方法是这样写的&#xff0c…

JavaScript 语言基础知识点总结(思维导图)

1.JavaScript数组 2.JavaScript 函数基础 3.Javascript 运算符 4.JavaScript 流程控制 5.JavaScript 正则表达式 6.JavaScript 变量 7.JavaScript 字符串函数 8.DOM 基本操作 制作工具&#xff1a;Mindjet MindManager 文章摘自&#xff1a;http://m.oschina.net/blog/175426转…

linux之一些比较新但是常用的命令(expr ag tree cloc stat tmux axel)

1 expr命令 介绍:这个命令用来匹配正则表达式,这个命令linux系统自带,不信你自己试下 使用:expr 正则表达式 输出结果 expr http:\/\/www\.baidu\.com http//www.baidu.com 用了这个命令,我们就不需要在网上去搞在线正则表达式匹配 2 tree命令 这个命令需要安装 sudo…

基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)

作者信息 作者: 彭东林 邮箱&#xff1a;pengdonglin137163.com QQ&#xff1a;405728433 平台简介 开发板&#xff1a;tiny4412ADK S700 4GB Flash 要移植的内核版本&#xff1a;Linux-4.4.0 &#xff08;支持device tree&#xff09; u-boot版本&#xff1a;友善之臂自带的…

【C语言简单说】八:分支结构之if...else if()...else...(3)

既然前面几种情况大家都了解了话&#xff0c;这一节的话我就不举例子了。。。 直接上代码&#xff1a; #include<stdio.h> #include<stdlib.h> int main() {int a1;if(a1){printf("a的值等于1\n");}else if(a2){printf("a的值等于2\n"); …

最通俗易懂的依赖注入与控制反转

这是一个关于 ASP.NET 6 依赖注入的系列文章。在这个系列中&#xff0c;我们将了解到什么是依赖注入、控制反转&#xff0c;它能够做什么&#xff0c;以及我们为什么要使用它。之后&#xff0c;我们会进一步了解 ASP.NET 6 依赖注入的生命周期、服务容器等重要概念。最后&#…

word公式编辑器_论文查重算公式吗 公式怎样避免查重?

论文查重算公式吗 公式怎样避免查重?每一个毕业生想要毕业都要经过论文查重这一关&#xff0c;仅有通过了论文查重&#xff0c;才可以进入答辩。在论文检测的情况下&#xff0c;不少同学论文中一定会应用大批量的计算公式&#xff0c;且计算公式全部都是固定不动的&#xff0c…

adb logcat 查看日志

使用 logcat 命令 查看和跟踪系统日志缓冲区的命令logcat的一般用法是&#xff1a; [adb] logcat [<option>] ... [<filter-spec>] ... 下文介绍过滤器和命令选项&#xff0c;详细内容可参见Listing of logcat Command Options。 可以在开发机中通过远程shell的方式…

小程序 - 学习笔记

一、小程序文档笔记 默认开发目录 开发目录解析 1.  app.js、app.json、app.wxss 这三个文件必须有不能删掉。 一个小程序主体部分由这三个文件组成&#xff0c;而且必须放在项目的根目录 js后缀的是脚本文件&#xff0c;调用小程序框架提供的 API—— API 文档json后缀的文件…

【C语言简单说】九:输入

到了下午了&#xff0c;上着班发现没啥事情做… 又来码博客了 ↖(▔&#xff3e;▔)↗ 这一小节我们来说说输入吧。突然想总结以下if语句的&#xff0c;结果发现&#xff0c;还有一个输入没说&#xff1b;之前是不是说过了输出&#xff1f;就是printf这个&#xff0c;现在还有…

java 优秀源码_想要快速进阶Java架构师?这份超强(长)学习计划单 请签收!...

优秀工程师的成长之路就是一条不断打怪升级之路的“修仙之路”&#xff01;而Java程序员一向比别人更难&#xff0c;如果说大家都在修仙的话&#xff0c;java程序员简直神似“剑修”&#xff0c;入行枯燥精通难&#xff0c;要想变得强大&#xff0c;需要能力也需要运气&#xf…

Web Api如何传递POST请求

这里记录一次Web Api传递post请求的例子&#xff0c;由于使用了默认工程的例子&#xff0c;方法名的参数值标记头为FromBody的形式&#xff0c;如下图所示的调用&#xff1a; 调用方式&#xff1a; 那么如果要两个以上的参数如何去实现&#xff0c;这种方式是不行的&#xff0c…

AOT和单文件发布对程序性能的影响

前言这里先和大家介绍一下.NET一些发布的历史&#xff0c;以前的.NET框架原生并不支持最终编译结果的单文件发布&#xff08;需要依赖第三方工具&#xff09;&#xff0c;我这里新建了一个简单的ASP.NET Core项目&#xff0c;发布以后的目录就会像下图这样&#xff0c;里面包含…

无法识别的属性“targetFramework”。请注意属性名称区分大小写。

asp.net部署出错(targetFramework无法识别) 今天尝试着部署了一个基于Framework4.0的web项目&#xff0c;途中发生了一点小小的意外。报的错误是Web.Config配置文件中的 targetFramework属性无法识别。后来查了一下发现在站点中部署的Web使用的是基于.Net Framework2.0的Applic…

.NET点滴:说说Middleware构造中获取不到Scoped服务的问题

今天小桂问我&#xff1a;“为什么中间件的构造函数里不能使用scope的生命周期类型啊&#xff1f;”&#xff0c;那就用实例来得到答案吧&#xff0c;先看小桂说的情况&#xff0c;是报错的&#xff1a;var builder WebApplication.CreateBuilder(args);builder.Services.AddS…