Asp.Net Core 中间件应用实践中你不知道的那些事

栏目: IT技术 · 发布时间: 4年前

内容简介:这篇文章主要分享可以点击查看以下两篇解读文章:我们知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终到达我们写的代码中。那么中间件就是在应用程序管道中的一个组件,用来拦截请求过程进行一些其他处理和响应。中间件可以有很多个,每一个中间件都可以对管道中的请求进行拦截,它可以决定是否将请求转移给下一个中间件。

一、概述

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

可以点击查看以下两篇解读文章:

1.1 中间件(Middleware)的作用

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

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

Asp.Net Core 中间件应用实践中你不知道的那些事

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?}");
            });
}

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

Asp.Net Core 中间件应用实践中你不知道的那些事

从调试的结果图中可以看出 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 )。

如果您觉的不错,请微信扫码关注 【dotNET博士】公众号,后续给您带来更精彩的分享

Asp.Net Core 中间件应用实践中你不知道的那些事

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


以上所述就是小编给大家介绍的《Asp.Net Core 中间件应用实践中你不知道的那些事》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

自品牌

自品牌

陈为、孙郁婷 / 机械工业出版社 / 2015-9-7 / 39

移动互联网来势汹涌,让品牌重新回到人的时代。微信旗帜鲜明地宣示,“再小的个体也有自己的品牌”。《自品牌:个人如何玩转移动互联网时代》作者历经一年,深度访谈10位嘉宾,挖掘其品牌与商业成功密码。吴晓波、雕爷、罗永浩、鬼脚七、马佳佳……这些商业新浪潮中的探路者与领军者,要么是传统领域的老将,要么是新领域里的先锋,但都能以新媒体为载体,构建个人品牌,打造商业生态,抓住互联网的时代红利,顺风而起,顺势而为......一起来看看 《自品牌》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具