.NET Core 自定义中间件 Middleware
引言
很多看了上一章的朋友私信博主,问如何自定义,自己的中间件(Middleware),毕竟在实际的项目中,大家会有很多需求要用到中间件,比如防盗链、缓存、日志等等功能,于是博主这边就简单讲解一下框架、组件惯用的优雅手法,官方也推荐这种写法,这样会使得我们扩展性更好,也不会破坏原本结构。
什么是中间件
中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:
- 选择是否将请求传递到管道中的下一个组件。
- 可在管道中的下一个组件前后执行工作。
使用 RunMap 和 Use 扩展方法来配置请求委托,请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。
简单的说,我们按需求决定使用哪些组件,程序运行时,一个HTTP请求过来,程序执行流程,是按照我们定义的组件顺序执行的。所以我们项目上的中间件放置顺序是不能乱的,并且不用的也不要装配,避免消耗性能。
概念图:
如果想做其他相关了解,博主建议直接在官网上看文档,微软的文档写的还是很好的,还提供的Demo下载,比很多网上博客讲的好。
微软官网地址:ASP.NET Core 中间件 | Microsoft Docs
接下来进入正题,我们写一个,把所有http请求地址发送到MQ的中间件:
1.编写MsgMiddleware类
这里我们就使用直接编写Middleware类的方式,大家也可以使用实现IMiddleware接口的方式。两种底层原理不一样:前者是框架启动时就实例化;后者是请求来时才实例化,用完立即释放。
编写Middleware类注意:
- 编写好InvokeAsync或者Invoke方法
- 构造函数参数需要一个RequestDelegate类型的委托
因为这块源码是直接通过反射创建和调用的,不过源码也会对我们的类进行规范校验。
代码逻辑:
这里我们就实现一个简单逻辑,根据Options配置SendFlag是否开启发送MQ,如果是,就调用我们的ISendMessage发送服务。服务获取方式大家也可以使用注入的方式
ISendMessage服务、Options配置类代码,我放到了后面讲解,毕竟逻辑简单,而且也不是重点。
查看代码
public class MsgMiddleware
{
private readonly RequestDelegate _next;
private readonly MsgOptions options;
/// <summary>
/// 管道执行到该中间件时候下一个中间件的RequestDelegate请求委托,如果有其它参数,也同样通过注入的方式获得
/// </summary>
/// <param name="next"></param>
public MsgMiddleware(RequestDelegate next, IOptions<MsgOptions> options)
{
//通过注入方式获得对象
_next = next;
this.options = options.Value;
}
/// <summary>
/// 自定义中间件要执行的逻辑
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task Invoke(HttpContext context)
{
if (options.SendFlag)
{
//通过IOC获取ISendMessage
ISendMessage _message = context.RequestServices.GetService<ISendMessage>();
_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<MsgMiddleware>();
}
//Use直接配置Options
public static IApplicationBuilder UseMsgSend(this IApplicationBuilder app, Action<MsgOptions> optionsAction)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
//1 不能直接初始化Option
//2 也不能找到ServiceCollection去初始化了
MsgOptions op = new MsgOptions();
optionsAction(op);
return app.UseMiddleware<MsgMiddleware>(Options.Create(op));
}
}
3.编写IServiceCollection容器扩展方法
这样的好处是,我们这样可以集中注册内部映射,隐藏实现细节,外部不需要关心,这个好处博主就不多说了,因为大家使用别人写的组件也心有体会,对于使用者来说只需要关心怎么用,他内部有多么复杂的逻辑是不知道的,也不需要知道.
这里也是编写两个扩展方法,用来应对在Use时候直接配置Options,或者后面通过IOC方式配置Options
代码逻辑:
这两个方法里面逻辑就是,注册好业务服务、Options 等等。。。
查看代码
/// <summary>
/// 这样可以集中注册内部映射,外部不需要关心
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// 配置信息初始化由Middleware
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddSendMessage(this IServiceCollection services)
{
return services.AddSingleton<ISendMessage, SendMessage>();
}
/// <summary>
/// 配置信息直接用Option的模式去初始化
/// </summary>
/// <param name="services"></param>
/// <param name="configure"></param>
/// <returns></returns>
public static IServiceCollection AddSendMessage(this IServiceCollection services, Action<MsgOptions> 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>? RabbitMQOptions { get; private set; }
public void Register(Action<RabbitMQOptions> action)
{
RabbitMQOptions = action;
}
}
//Msg配置扩展方法,用来设置其MQ配置信息
public static class MsgOptionsExtensions
{
public static void UseRabbitMQ(this MsgOptions options, Action<RabbitMQOptions> 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<RabbitMQOptions> rabbitMQ)
{
this.rabbitMQ = rabbitMQ.Value;
}
public void Send(string message)
{
Console.WriteLine($"发送消息:{message},至--->{rabbitMQ.IP}:{rabbitMQ.Port}服务器");
}
}
6.使用自定义中间件
我们只需要调用我们定义的扩展方法即可,博主这里用的.NET 6,使用的顶级语句。老版本的朋友就在Startup类里配置,调用方式是一样的
如下:
- Configure方法里使用,app.UseMsgSend()
- 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();
运行效果
如图,我们请求多少次,请求都会经过我们中间件。
.NET Core 自定义中间件 Middleware的更多相关文章
- 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?
原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...
- ASP.NET Core 开发-中间件(Middleware)
ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下一个组件的请求,并能之前和下一组 ...
- 如何传递参数给ASP.NET Core的中间件(Middleware)
问题描述 当我们在ASP.NET Core中定义和使用中间件(Middleware)的时候,有什么好的办法可以给中间件传参数吗? 解决方案 在ASP.NET Core项目中添加一个POCO类来传递参数 ...
- ASP.NET Core自定义中间件的方式
ASP.NET Core应用本质上,其实就是由若干个中间件构建成的请求处理管道.管道相当于一个故事的框架,而中间件就相当于故事中的某些情节.同一个故事框架采用不同的情节拼凑,最终会体现出不同风格的故事 ...
- asp.net core 自定义中间件和service
首先新建项目看下main方法: public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel ...
- asp.net core 系列之中间件进阶篇-编写自定义中间件(middleware)
中间件是被用到管道(pipeline)上来处理请求(request)和响应的(response). asp.net core 本身提供了一些内置的中间件,但是有一些场景,你可能会需要写一些自定义的中间 ...
- asp.net core 自定义中间件
官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1 中间件的定 ...
- asp.net core 自定义中间件【以dapper为例】
在asp.net core开发中.按照国际案例开始.都是先在Nuget安装XXX包.比如我们今天要用到的Dapper nuget里面安装Dapper 1.然后新建一个类文件DapperExtensio ...
- django 自定义中间件 middleware
Django 中间件 Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出.中间件的设计为开发者提供了一种无侵入式的开发方式,增强 ...
随机推荐
- JAVA火星坐标系、百度坐标系、84坐标系相互转换工具类
/** * 坐标系转换工具类 */ public class PositionUtil { public static double pi = 3.1415926535897932384626; pu ...
- office2007(word2007)另存为pdf文档
默认office2007(word2007)是没有另存为pdf文档的功能的,需要安装插件 插件地址:https://yvioo.lanzous.com/iO5myedoceh 下载之后直接安装,安装成 ...
- 在制造业的工业2.0中应用MOM系统
介绍 什么是制造运营管理 (MOM) 系统和 IT 架构的最佳实践? 行业专家对制造类型和供应网络有何建议? 管理思维和企业文化是否因不断变化的全球市场而过时? MOM 技术是否过于昂贵,IT 架构是 ...
- Django网站实例效果
Django是一种开源的大而且全的Web应用框架,是由python语言来编写的,优点十分明显: 功能完善.要素齐全:自带大量常用工具和框架(比如分页,auth,权限管理), 适合快速开发企业级网站. ...
- Codeforces 1113C: Sasha and a Bit of Relax(位运算|异或)
time limit per test: 1 secondmemory limit per test: 256 megabytesinput: standard inputoutput: standa ...
- 「算法笔记」快速数论变换(NTT)
一.简介 前置知识:多项式乘法与 FFT. FFT 涉及大量 double 类型数据操作和 \(\sin,\cos\) 运算,会产生误差.快速数论变换(Number Theoretic Transfo ...
- 大数据分布式存储之Cassandra
分布式存储区别于集中式数据库存储,通过网络将海量数据存储到企业的各个数据节点(可能分布到不同的数据中心或机架上): 分布式存储需要考虑的问题 元数据管理 元数据是指数据本身的标识,通过元数据能很快的找 ...
- MySQL8.0的下载与安装
下载 进入官网的下载页面 点击下图中的链接 可以选择上边的 Community Server ,那样会下载压缩包,这里我选择下边的 Installer for Windows ,下载的是安装包 点击下 ...
- BL8810最新版规格书|BL8810方案|USB 2.0读卡器控制器
在数码产品越来越普及的今天,利用单反.手机.平板等产品随手拍下相片.储存一些非常重要的数据等已经成为很多人必做的事情,而除使用数据线进行数据导入导出的操作外,利用读卡器也是一个必然的选择,就以本人自己 ...
- PHP 中的多进程使用,进程通信、进程信号等详解
多进程环境要求 Linux 系统 php-cli 模式 pcntl 扩展 或 swoole 扩展 pcntl 扩展 <?php $str = "hello world!" . ...