一、概述

这篇文章主要分享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)。

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

Asp.Net Core Endpoint 终结点路由之中间件应用的更多相关文章

  1. Asp.Net Core EndPoint 终点路由工作原理解读

    一.背景 在本打算写一篇关于Identityserver4 的文章时候,确发现自己对EndPoint -终结点路由还不是很了解,故暂时先放弃了IdentityServer4 的研究和编写:所以才产生了 ...

  2. Asp.Net Core 第06局:中间件

    总目录 前言 本文介绍Asp.Net Core 中间件. 环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 第一手:中间件概述     1.中间件:添加到应用 ...

  3. ASP.NET Core MVC 之路由(Routing)

     ASP.NET Core MVC 路由是建立在ASP.NET Core 路由的,一项强大的URL映射组件,它可以构建具有理解和搜索网址的应用程序.这使得我们可以自定义应用程序的URL命名形式,使得它 ...

  4. 在ASP.NET Core中构建路由的5种方法

    原文链接 :https://stormpath.com/blog/routing-in-asp-net-core 在ASP.NET Core中构建路由的5种方法 原文链接 :https://storm ...

  5. C#调用接口注意要点 socket,模拟服务器、客户端通信 在ASP.NET Core中构建路由的5种方法

    C#调用接口注意要点   在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用, 所以首先需要通过调用登录接口来保存c ...

  6. ASP.NET Core MVC的路由参数中:exists后缀有什么作用,顺便谈谈路由匹配机制

    我们在ASP.NET Core MVC中如果要启用Area功能,那么会看到在Startup类的Configure方法中是这么定义Area的路由的: app.UseMvc(routes => { ...

  7. asp.net core 3.x Endpoint终结点路由1-基本介绍和使用

    前言 我是从.net 4.5直接跳到.net core 3.x的,感觉asp.net这套东西最初是从4.5中的owin形成的.目前官方文档重点是讲路由,没有特别说明与传统路由的区别,本篇主要介绍终结点 ...

  8. Asp .Net core 2 学习笔记(2) —— 中间件

    这个系列的初衷是便于自己总结与回顾,把笔记本上面的东西转移到这里,态度不由得谨慎许多,下面是我参考的资源: ASP.NET Core 中文文档目录 官方文档 记在这里的东西我会不断的完善丰满,对于文章 ...

  9. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

随机推荐

  1. winform 界面加载慢原因分析

    公司新来的开发人员,对winform开发还不是特别精通,在做个性化界面体验的时候容易出现闪烁和加载慢 闪烁的话,通过winform窗体的双缓存来解决在form 窗体中增加如下代码 protected ...

  2. 吴裕雄--天生自然python机器学习:机器学习简介

    除却一些无关紧要的情况,人们很难直接从原始数据本身获得所需信息.例如 ,对于垃圾邮 件的检测,侦测一个单词是否存在并没有太大的作用,然而当某几个特定单词同时出现时,再辅 以考察邮件长度及其他因素,人们 ...

  3. D. Almost All Divisors

    We guessed some integer number xx. You are given a list of almost all its divisors. Almost all means ...

  4. T-shirt

    题目描述 JSZKC is going to spend his vacation!  His vacation has N days. Each day, he can choose a T-shi ...

  5. LiauidCrystal

    1.begin()函数语法: lcd.begin(cols,rows) cols:列数: rows:行数: 2.print()函数,语法: lcd.print(data) lcd.print(data ...

  6. 【转】Vim命令合集

    Vim命令合集 命令历史 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令. 启动vim 在命令行窗口中输入以下命令即可 vim 直接启动vim vim filena ...

  7. Yii框架的学习指南(策码秀才篇)1-2 一步步学习yii framework

    我也是新手,不过之前学习了tp和ci框架,所以尝鲜想看看yii到底有多强大. 如何新建一个webapp(网站应用)呢,下面是2个步骤: 1. cmd 切换到htdocs下面的yii目录下的framew ...

  8. Qt QByteArray 与 char* 的转换

    QByteArray 转换为 char * char *ch;//不要定义成ch[n]; QByteArray byte; ch = byte.data(); char * 转换为 QByteArra ...

  9. 年轻的心与渐行渐近的梦——记微软-斯坦福产品设计创新课程ME310

    作者:中国科学技术大学 王牧 Stanford  D. School 2014年6月,沐浴着加州的阳光,在斯坦福大学(下文简称Stanford)完成汇报后,历时一年的创新设计课程ME310的项目结束 ...

  10. sql语句查询成绩表各科前三名

    --语法形式: ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2) --解释: 根据COL1分组,在分组内部根据 COL2排序,而此函数计算的值就表示 ...