asp.netcore中间件应用实践中你不知道的那些事(代码片段)

Jlion Jlion     2022-12-24     640

关键词:

一、概述

这篇文章主要分享Endpoint 终结点路由的中间件的应用场景及实践案例,不讲述其工作原理,如果需要了解工作原理的同学,
可以点击查看以下两篇解读文章:

1.1 中间件(Middleware)的作用

我们知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终到达我们写的代码中。那么中间件就是在应用程序管道中的一个组件,用来拦截请求过程进行一些其他处理和响应。中间件可以有很多个,每一个中间件都可以对管道中的请求进行拦截,它可以决定是否将请求转移给下一个中间件。

asp.net core 提供了IApplicationBuilder接口来让把中间件注册到asp.net的管道请求当中去,中间件是一个典型的AOP应用。 下面是一个微软官方的一个中间件管道请求图:

1.2 中间件和过滤器的区别

Filter是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。
具体可以查看我上次分享的一篇Asp.Net Core Filter 深入浅出的那些事-AOP 的文章.

根据描述,可以看出中间件和过滤器的功能类似,那么他们有什么区别?为什么又要搞一个中间件呢?
其实,过滤器和中间件他们的关注点是不一样的,也就是说职责不一样,干的事情就不一样。

同作为两个AOP利器,Filter(过滤器)更贴合业务,它关注于应用程序本身,比如你看ActionFilterResultFilter,它都直接和你的ActionActionResult交互了,是不是离你很近的感觉,那我有一些比如对我的输出结果进行格式化,对我的请求的ViewModel进行数据验证啦,肯定就是用Filter无疑了。它是MVC的一部分,它可以拦截到你Action上下文的一些信息,而中间件是没有这个能力的。

可以看到,每一个中间件都都可以在请求之前和之后进行操作。请求处理完成之后传递给下一个请求

1.3 中间件的使用场景

那么,何时使用中间件呢?我的理解是在我们的应用程序当中和业务关系不大的一些需要在管道中做的事情可以使用,比如身份验证,Session存储,日志记录等。其实我们的 Asp.net core项目中本身已经包含了很多个中间件。比如 身份认证中间件 UseAuthorization()等系列.

二、中间件实战

需求场景:通过后端记录每一次的访问请求日志,同时需要根据需要排除一些Controller 或者Action 不记录请求的日志信息。

思考:经过分析我需要创建一个全局的中间件进行拦截路由,并且写入日志;同时需要添加一个特性Attribute 进行标注那些Controller或者Action 不需要进行日志记录。

我们来创建LogsMiddleware 中间件代码,代码如下:

public class LogsMiddleware

        private readonly RequestDelegate _next;

        public LogsMiddleware(RequestDelegate next)
        
            this._next = next;
        

        public async Task Invoke(HttpContext context)
        
            var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;
            if (endpoint == null)
            
                await _next(context);
                return;
            

            using (var scope = context.RequestServices.CreateScope())
            
                var _logger = scope.ServiceProvider.GetService<ILogger<LogsMiddleware>>();

                var attruibutes = endpoint.Metadata.OfType<NoLogsAttriteFilter>();
                if (attruibutes.Count()==0)
                
                    _logger.LogInformation($" url:context.Request.Path, 访问时间:DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")");
                

                //记录 排除的特殊Message 信息
                foreach (var attribute in attruibutes)
                
                    _logger.LogInformation(attribute.Message);
                
            
            await _next(context);
        

NoLogsAttriteFilter 过滤器代码如下:

public class NoLogsAttriteFilter : Attribute

        /// <summary>
        /// 这里加这个主要是把获取到的信息在中间件中打印出来,区分中间件的拦截用处
        /// </summary>
        public string Message = "";

        public NoLogsAttriteFilter(string message)
        
            Message = message;
        

Startup 中的代码如下:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            
            else
            
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            

            app.UseRouting();
            app.UseAuthorization();
            app.UseMiddleware<LogsMiddleware>();//添加日志记录中间件
            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "controller=Home/action=Index/id?");
            );

HomeController 控制器中的两个Action 代码如下::

// 访问该路由会记录访问日志
public IActionResult Index()

        return View();


//访问该路由不会记录访问日志
[NoLogsAttriteFilter("Manage 不需要记录访问日志")]
public IActionResult Manage()

       return View();

这样就自定义日志中间件就已经完成了我上面的需求,不依赖于任何业务独立存在于系统中;从代码中我们可以看到中间件通过context.Features.Get<IEndpointFeature>()?.Endpoint; 方法获得终结点路由方式进行匹配,并且可以通过endpoint.Metadata.OfType<NoLogsAttriteFilter>() 方式获得Action 中的特性信息数据,并通过该拦截进行我的需求
自定义中间件教程文章请点击自定义中间件官方教程 一文。

现在我们再来印证下我上一篇关于 Asp.Net Core EndPoint 终结点路由工作原理解读 一文 中提及到UseRouting() 中间件是遍历所有的Endpoint 终结点路由以匹配当前请求的 Endpoint 终结点路由一说,我把注册LogsMiddleware中间件和UseRouting() 路由中间件代码顺序调整一下,代码如下:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            
            else
            
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            

			// 中间件注册放到了UseRouting() 之前
            app.UseMiddleware<LogsMiddleware>();//添加日志记录中间件
            
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "controller=Home/action=Index/id?");
            );

再来看看运行调试的结果如图:
运行调试结果

从调试的结果图中可以看出 endpoint 变量是 null;所有需要使用到Endpoint 终结点路由必须注册在UseRouting() 中间件之后。

三、官方常用中间件

  1. 异常/错误处理
    当应用在开发环境中运行时:
    开发人员异常页中间件 (UseDeveloperExceptionPage) 报告应用运行时错误。
    数据库错误页中间件报告数据库运行时错误。
    当应用在生产环境中运行时:
    异常处理程序中间件 (UseExceptionHandler) 捕获以下中间件中引发的异常。
    HTTP 严格传输安全协议 (HSTS) 中间件 (UseHsts) 添加 Strict-Transport-Security 标头。
  2. HTTPS 重定向中间件 (UseHttpsRedirection) 将 HTTP 请求重定向到 HTTPS。
  3. 静态文件中间件 (UseStaticFiles) 返回静态文件,并简化进一步请求处理。
  4. Cookie 策略中间件 (UseCookiePolicy) 使应用符合欧盟一般数据保护条例 (GDPR) 规定。
  5. 用于路由请求的路由中间件 (UseRouting)。
  6. 身份验证中间件 (UseAuthentication) 尝试对用户进行身份验证,然后才会允许用户访问安全资源。
  7. 用于授权用户访问安全资源的授权中间件 (UseAuthorization)。
  8. 会话中间件 (UseSession) 建立和维护会话状态。 如果应用使用会话状态,请在 Cookie 策略中间件之后和 MVC 中间件之前调用会话中间件。
  9. 用于将 Razor Pages 终结点添加到请求管道的终结点路由中间件(带有 MapRazorPages 的 UseEndpoints)。

以上如果有错误的地方,请大家积极纠正,谢谢大家的支持!!

netcore国际化最佳实践(代码片段)

NetCore国际化最佳实践ASP.NETCore中提供了一些本地化服务和中间件,可将网站本地化为不同的语言文化。ASP.NETCore中我们可以使用Microsoft.AspNetCore.Localization库来实现本地化。但是默认只支持使用资源文件方式做多语言存储,... 查看详情

asp.netcore中间件详解及项目实战(代码片段)

原文:ASP.NETCore中间件详解及项目实战前言在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的HelloWorld,如果你觉得本篇文... 查看详情

从asp.netmvc迁移到asp.netcoremvc

...打开"启动.cs"文件:C#ASP.NETCore应用必须选择包含中间件的框架功能。上一个模板生成的代码添加以下服务和中间件:此现有配置包括将示例ASP.NETMVC项目迁移所需的内容。有关ASP.NETCore中间件选项的详细信息,请参阅ASP.NETC... 查看详情

asp.netcore中间件基本用法(代码片段)

ASP.NETCore中间件ASP.NETCore的处理流程是一个管道,而中间件是装配到管道中的用于处理请求和响应的组件。中间件按照装配的先后顺序执行,并决定是否进入下一个组件。中间件管道的处理流程如下图(图片来源于官网):管道... 查看详情

asp.netcore中托管spa应用

...的spa功能。针对这个,我们可能首先想到的是自定义一个中间件进行处理,当请求特定path,以及静态资源是,加载对应文件夹下的spa应用文件。其实微软早就为我们准备好了这个中间件。这个中间件在:Microsoft.AspNetCore.SpaServices... 查看详情

asp.netcore中的缓存[1]:如何在一个asp.netcore应用中使用缓存

...持。除了这个独立的缓存系统之外,ASP.NETCore还借助一个中间件实现了“响应缓存”,它会按照HTTP缓存规范对整个 查看详情

asp.netcore第06局:中间件(代码片段)

总目录前言本文介绍Asp.NetCore中间件。环境1.VisualStudio20172.Asp.NetCore2.2开局第一手:中间件概述  1.中间件:添加到应用管道用于处理处理请求和响应的组件。每个组件:-可以选择是否将请求传递到管道中的下一个组件;-... 查看详情

[netcore]asp.netcore中间件(代码片段)

基本概念中间件是一种装配到应用管道以处理请求和响应的软件。每个组件:选择是否将请求传递到管道中的下一个组件。可在管道中的下一个组件前后执行工作。请求委托用于生成请求管道。请求委托处理每个HTTP请求。使... 查看详情

[netcore]asp.netcore中间件(代码片段)

基本概念中间件是一种装配到应用管道以处理请求和响应的软件。每个组件:选择是否将请求传递到管道中的下一个组件。可在管道中的下一个组件前后执行工作。请求委托用于生成请求管道。请求委托处理每个HTTP请求。使... 查看详情

「译」foreach循环中你不知道的3件事(代码片段)

前言本文925字,阅读大约需要7分钟。总括:forEach循环中你不知道的3件事。原文地址:3thingsyoudidn’tknowabouttheforEachloopinJS公众号:「前端进阶学习」,回复「666」,获取一揽子前端技术书籍自弃者扶不起,自强者击不倒。正文你... 查看详情

asp.netcore中间件详解及项目实战(代码片段)

原文:ASP.NETCore中间件详解及项目实战前言在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的HelloWorld,如果你觉得本篇文... 查看详情

asp.netcore管道详解[4]:中间件委托链(代码片段)

...象分发给它的请求。而RequestDelegate对象实际上是由所有的中间件按照注册顺序创建的。换句话说,这个RequestDelegate对象是对中间件委托链的体现。如果将RequestDele 查看详情

《asp.netcore6框架揭秘》实例演示[02]:基于路由mvc和grpc的应用开发

...管道的请求处理模型,这个管道由一个服务器和多个中间件构成,而与路由相关的EndpointRoutingMiddleware和EndpointMiddleware是两个最为重要的中间件。MVC和gRPC开发框架就建立在路由基础上。本篇提供了四个实例用来演示如何利... 查看详情

学习asp.netcore,怎能不了解请求处理管道[4]:应用的入口——startup

...味着管道的成功构建。由于管道是由注册的服务器和若干中间件构成的,所以应用启动过程中一个核心的工作就是完成中间节的注册。由于依赖注入在ASP.NETCore应用这得到非常广泛的应用,框架绝大部分的工作都会分配给我们预... 查看详情

asp.netcore在centos上的最小化部署实践(代码片段)

原文:ASP.NETCore在CentOS上的最小化部署实践引言    本文从Linux小白的视角,在CentOS7.x服务器上搭建一个Nginx-PoweredAspNetCoreWeb准生产应用。在开始之前,我们还是重温一下部署原理,正如你所常见的.NetCore部署图:在Lin... 查看详情

asp.netcore安全防护-客户端ip白名单限制(代码片段)

...使用以下2种方式:用于检查每个请求的远程IP地址的中间件。MVC操作筛选器,用于检查针对特定控制器或操作方法的请求的远程IP地址。中间件Startup.Configure方法将自定义 AdminSafeListMiddleware 中间件类型添加到应用的请求... 查看详情

一题多解,asp.netcore应用启动初始化的n种方案[上篇]

ASP.NETCore应用本质上就是一个由中间件构成的管道,承载系统将应用承载于一个托管进程中运行起来,其核心任务就是将这个管道构建起来。在ASP.NETCore的发展历史上先后出现了三种应用承载的编程方式,而且后一种... 查看详情

js中你不知道的一些概念知识(代码片段)

DOM元素e的e.getAttribute(propName)和e.propName有什么区别和联系e.getAttribute(),是标准DOM操作文档元素属性的方法,具有通用性可在任意文档上使用,返回元素在源文件中设置的属性e.propName通常是在HTML文档中访问特定元素的... 查看详情