热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

.NETCore自定义中间件Middleware

.NETCore自定义中间件Middleware-引言很多看了上一章的朋友私信博主,问如何自定义,自己的中间件(Middleware),毕竟在实际的项目中,大家会有很多需求要用

引言

很多看了上一章的朋友私信博主,问如何自定义,自己的中间件(Middleware),毕竟在实际的项目中,大家会有很多需求要用到中间件,比如防盗链、缓存、日志等等功能,于是博主这边就简单讲解一下框架、组件惯用的优雅手法,官方也推荐这种写法,这样会使得我们扩展性更好,也不会破坏原本结构。

什么是中间件

中间件是一种装配到应用管道以处理请求响应的软件。 每个组件:

  • 选择是否将请求传递到管道中的下一个组件。
  • 可在管道中的下一个组件前后执行工作。

使用 RunMap 和 Use 扩展方法来配置请求委托,请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。

简单的说,我们按需求决定使用哪些组件,程序运行时,一个HTTP请求过来,程序执行流程,是按照我们定义的组件顺序执行的。所以我们项目上的中间件放置顺序是不能乱的,并且不用的也不要装配,避免消耗性能。

概念图:

如果想做其他相关了解,博主建议直接在官网上看文档,微软的文档写的还是很好的,还提供的Demo下载,比很多网上博客讲的好。

微软官网地址:ASP.NET Core 中间件 | Microsoft Docs

接下来进入正题,我们写一个,把所有http请求地址发送到MQ的中间件:

1.编写MsgMiddleware类

这里我们就使用直接编写Middleware类的方式,大家也可以使用实现IMiddleware接口的方式。两种底层原理不一样:前者是框架启动时就实例化;后者是请求来时才实例化,用完立即释放。

编写Middleware类注意:

  1. 编写好InvokeAsync或者Invoke方法
  2. 构造函数参数需要一个RequestDelegate类型的委托

因为这块源码是直接通过反射创建和调用的,不过源码也会对我们的类进行规范校验。

代码逻辑:

这里我们就实现一个简单逻辑,根据Options配置SendFlag是否开启发送MQ,如果是,就调用我们的ISendMessage发送服务。服务获取方式大家也可以使用注入的方式

ISendMessage服务Options配置代码,我放到了后面讲解,毕竟逻辑简单,而且也不是重点。

查看代码
public class MsgMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly MsgOptions options;
        /// 
        /// 管道执行到该中间件时候下一个中间件的RequestDelegate请求委托,如果有其它参数,也同样通过注入的方式获得
        /// 
        /// 
        public MsgMiddleware(RequestDelegate next, IOptions options)
        {
            //通过注入方式获得对象
            _next = next;
            this.optiOns= options.Value;
        }

        /// 
        /// 自定义中间件要执行的逻辑
        /// 
        /// 
        /// 
        public async Task Invoke(HttpContext context)
        {
            if (options.SendFlag)
            {
                //通过IOC获取ISendMessage
                ISendMessage _message = context.RequestServices.GetService();
                _message.Send(context.Request.Path.Value);
            }
            //把context传进去执行下一个中间件
            await _next(context);
        }
    }

2.编写IApplicationBuilder扩展方法

这里我们就定义两个扩展方法,用来应对在Use时候直接配置Options,或者后面通过IOC方式配置Options

注意:如果在Use时候直接配置参数,我们的Options需要通过Options.Create(op)帮我们包裹成IOptions<>类型,因为编写的中间件参数是Options模式的一个IOptions接口

查看代码
public static class MsgBuilderMiddlewareExtensions
    {
        //没有Option,依靠IOC的Add的方式设置
        public static IApplicationBuilder UseMsgSend(this IApplicationBuilder app)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }
            return app.UseMiddleware();
        }

        //Use直接配置Options
        public static IApplicationBuilder UseMsgSend(this IApplicationBuilder app, Action optionsAction)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }
            //1  不能直接初始化Option
            //2  也不能找到ServiceCollection去初始化了
            MsgOptions op = new MsgOptions();
            optionsAction(op);
            return app.UseMiddleware(Options.Create(op));
        }
    }

3.编写IServiceCollection容器扩展方法

这样的好处是,我们这样可以集中注册内部映射,隐藏实现细节,外部不需要关心,这个好处博主就不多说了,因为大家使用别人写的组件也心有体会,对于使用者来说只需要关心怎么用,他内部有多么复杂的逻辑是不知道的,也不需要知道.

这里也是编写两个扩展方法,用来应对在Use时候直接配置Options,或者后面通过IOC方式配置Options

代码逻辑:

这两个方法里面逻辑就是,注册好业务服务、Options 等等。。。

查看代码
/// 
    /// 这样可以集中注册内部映射,外部不需要关心
    /// 
    public static class ServiceCollectionExtensions
    {
        /// 
        /// 配置信息初始化由Middleware
        /// 
        /// 
        /// 
        public static IServiceCollection AddSendMessage(this IServiceCollection services)
        {
            return services.AddSingleton();
        }

        /// 
        /// 配置信息直接用Option的模式去初始化
        /// 
        /// 
        /// 
        /// 
        public static IServiceCollection AddSendMessage(this IServiceCollection services, Action configure)
        {
            MsgOptions msg = new MsgOptions();
            configure(msg);
            services.Configure(configure);
            services.Configure(msg.RabbitMQOptions);
            return services.AddSendMessage();
        }
    }

4.定义Options类

定义好我们业务逻辑需要的配置信息Options类

查看代码
//MQ配置类
    public class RabbitMQOptions
    {
        public string IP { get; set; }
        public string Port { get; set; }
    }
    //Msg配置类
    public class MsgOptions
    {
        //是否发送
        public bool SendFlag { get; set; }
        //MQ配置
        internal Action? RabbitMQOptions { get; private set; }

        public void Register(Action action)
        {
            RabbitMQOptiOns= action;
        }
    }
    //Msg配置扩展方法,用来设置其MQ配置信息
    public static class MsgOptionsExtensions
    {
        public static void UseRabbitMQ(this MsgOptions options, Action configure)
        {
            if (cOnfigure== null)
            {
                throw new ArgumentNullException(nameof(configure));
            }
            options.Register(configure);
        }
    }

5.编写Msg服务

这里我们就用打印信息的方式来表示我们将数据发送至MQ了

 public interface ISendMessage
    {
        void Send(string message);
    }
    public class SendMessage : ISendMessage
    {
        private readonly RabbitMQOptions rabbitMQ;
        public SendMessage(IOptions rabbitMQ)
        {
            this.rabbitMQ = rabbitMQ.Value;
        }
        public void Send(string message)
        {
            Console.WriteLine($"发送消息:{message},至--->{rabbitMQ.IP}:{rabbitMQ.Port}服务器");
        }
    }

6.使用自定义中间件

我们只需要调用我们定义的扩展方法即可,博主这里用的.NET 6,使用的顶级语句。老版本的朋友就在Startup类里配置,调用方式是一样的

如下:

  1. Configure方法里使用,app.UseMsgSend()
  2. ConfigureServices方法里使用,services.AddSendMessage(x=>{...})
查看代码
using WebApplication1.MiddlewareExp;
using WebApplication1.MiddlewareExp.Middleware;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

//配置中间件配置信息
builder.Services.AddSendMessage(c =>
{
    c.SendFlag = true;
    c.UseRabbitMQ(x =>
    {
        x.IP = "127.0.0.1";
        x.Port = "8080";
    });
});



var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

// 使用自定义的Msg中间件
app.UseMsgSend();

app.UseAuthorization();

app.MapControllers();

app.Run();

运行效果

如图,我们请求多少次,请求都会经过我们中间件。


推荐阅读
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 高效解决应用崩溃问题!友盟新版错误分析工具全面升级
    友盟推出的最新版错误分析工具,专为移动开发者设计,提供强大的Crash收集与分析功能。该工具能够实时监控App运行状态,快速发现并修复错误,显著提升应用的稳定性和用户体验。 ... [详细]
  • andr ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细探讨了Java中的24种设计模式及其应用,并介绍了七大面向对象设计原则。通过创建型、结构型和行为型模式的分类,帮助开发者更好地理解和应用这些模式,提升代码质量和可维护性。 ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
  • 网络攻防实战:从HTTP到HTTPS的演变
    本文通过一系列日记记录了从发现漏洞到逐步加强安全措施的过程,探讨了如何应对网络攻击并最终实现全面的安全防护。 ... [详细]
  • 该平台旨在为大型企业提供一个高效、灵活且可扩展的分布式微服务架构解决方案。它采用模块化、微服务化和热部署的设计理念,结合当前最先进且无商业限制的主流开源技术,如Spring Cloud、Spring Boot2、MyBatis、OAuth2和Element UI,实现前后端分离的系统管理平台。 ... [详细]
  • libsodium 1.0.15 发布:引入重大不兼容更新
    最新发布的 libsodium 1.0.15 版本带来了若干不兼容的变更,其中包括默认密码散列算法的更改和其他重要调整。 ... [详细]
  • VSCode与Gitee集成:项目提交的高效实践
    本文介绍如何利用VSCode内置的Git工具将项目提交到Gitee,简化Git命令的使用,提升代码管理效率。同时分享一些常见的踩坑经验和解决方案。 ... [详细]
  • 本文详细介绍了MicroATX(也称Mini ATX)和MATX主板规格,探讨了它们的结构特点、应用场景及对电脑系统成本和性能的影响。同时,文章还涵盖了相关操作系统的实用技巧,如蓝牙设备图标删除、磁盘管理等。 ... [详细]
author-avatar
拍友2502916683
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有