net core 中间件详解及项目实战
net core 中间件详解及项目实战
前言
在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World,如果你觉得本篇文章对你有用的话,不妨点个【推荐】。
目录
- 中间件(Middleware)的作用
- 中间件的运行方式
- 中间件(Middleware)和过滤器(Filter)的区别
- 什么情况我们需要中间件
- 怎么样自定义自己的中间件
中间件(Middleware)的作用
我们知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终到达我们写的代码中。那么中间件就是在应用程序管道中的一个组件,用来拦截请求过程进行一些其他处理和响应。中间件可以有很多个,每一个中间件都可以对管道中的请求进行拦截,它可以决定是否将请求转移给下一个中间件。
asp.net core 提供了IApplicationBuilder接口来让把中间件注册到asp.net的管道请求当中去,中间件是一个典型的AOP应用。 下面是一个微软官方的一个中间件管道请求图:
可以看到,每一个中间件都都可以在请求之前和之后进行操作。请求处理完成之后传递给下一个请求。
中间件的运行方式
默认情况下,中间件的执行顺序根据Startup.cs文件中,在public void Configure(IApplicationBuilder app){} 方法中注册的先后顺序执行。
大概有3种方式可以在管道中注册"中间件"
app.Use(),IApplicationBuilder接口原生提供,注册等都用它。app.Run(),是一个扩展方法,它需要一个RequestDelegate委托,里面包含了Http的上下文信息,没有next参数,因为它总是在管道最后一步执行。app.Map(),也是一个扩展方法,类似于MVC的路由,用途一般是一些特殊请求路径的处理。如:www.example.com/token 等。
上面的Run,Map内部也是调用的Use,算是对IApplicationBuilder接口扩充,如果你觉得名字都不够准确,那么下面这个扩展方法就是正宗的注册中间件的了,也是功能最强大的。app.UseMiddleware<>(),没错,就是这个了。 为什么说功能强大呢?是因为它不但提供了注册中间件的功能,还提供了依赖注入(DI)的功能,以后大部分情况就用它了。
中间件(Middleware)和过滤器(Filter)的区别
熟悉MVC框架的同学应该知道,MVC也提供了5大过滤器供我们用来处理请求前后需要执行的代码。分别是AuthenticationFilter,AuthorizationFilter,ActionFilter,ExceptionFilter,ResultFilter。
根据描述,可以看出中间件和过滤器的功能类似,那么他们有什么区别?为什么又要搞一个中间件呢?
其实,过滤器和中间件他们的关注点是不一样的,也就是说职责不一样,干的事情就不一样。
举个栗子,中间件像是
埃辛诺斯战刃,过滤器像是巨龙之怒,泰蕾苟萨的寄魂杖,你一个战士拿着巨龙之怒,泰蕾苟萨的寄魂杖去战场杀人,虽然都有伤害,但是你拿着法杖伤害低不说,还减属性啊。
同作为两个AOP利器,过滤器更贴合业务,它关注于应用程序本身,比如你看ActionFilter 和 ResultFilter,它都直接和你的Action,ActionResult交互了,是不是离你很近的感觉,那我有一些比如对我的输出结果进行格式化啦,对我的请求的ViewModel进行数据验证啦,肯定就是用Filter无疑了。它是MVC的一部分,它可以拦截到你Action上下文的一些信息,而中间件是没有这个能力的。
什么情况我们需要中间件
那么,何时使用中间件呢?我的理解是在我们的应用程序当中和业务关系不大的一些需要在管道中做的事情可以使用,比如身份验证,Session存储,日志记录等。其实我们的 asp.net core项目中本身已经包含了很多个中间件。
举例,我们在新建一个 asp.net core应用程序的时候,默认生成的模板当中
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseDeveloperExceptionPage();
app.UseStaticFiles();
loggerFactory.AddConsole();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
懒得去下载源码了,我们使用Reflector去查看源码:
//扩展方法`app.UseDeveloperExceptionPage();`
public static class DeveloperExceptionPageExtensions
{
// Methods
public static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException("app");
}
return UseMiddlewareExtensions.UseMiddleware<DeveloperExceptionPageMiddleware>(app, Array.Empty<object>());
}
}
//扩展方法`app.UseStaticFiles();`
public static class StaticFileExtensions
{
// Methods
public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException("app");
}
return UseMiddlewareExtensions.UseMiddleware<StaticFileMiddleware>(app, Array.Empty<object>());
}
}
可以看到 app.UseDeveloperExceptionPage(),app.UseStaticFiles()等等都是通过中间件实现的。
怎么样自定义自己的中间件
背景:我们项目使用到中间件的情景是,需要和其他部门进行用户(User)信息的共享。 以平台和子系统举例,我们正在开发一个子系统,其中用户信息,登录,注册等功能是放在平台上的,这是一个跨多语言的系统,平台是Java语言开发,用户在访问子系统的一些页面的时候需要验证是否登录,另外一些页面是不需要验证是否登录的,所以需要一个身份验证系统来代替Identity的功能。
幸运的是微软已经给我们提供了一套身份验证的中间件,在Microsoft.AspNetCore.Authentication命名空间下,我们只需要拓展,添加自己的功能就行了 。具体怎么做呢?直接看代码吧。
根据约定俗成,中间件类需要有一个Invoke方法,签名是public async Task Invoke(HttpContext context){},下面是一个中间件的示例类:
public class RequestLoggerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_next = next;
_logger = loggerFactory.CreateLogger<RequestLoggerMiddleware>();
}
public async Task Invoke(HttpContext context)
{
_logger.LogInformation("Handling request: " + context.Request.Path);
await _next.Invoke(context);
_logger.LogInformation("Finished handling request.");
}
}
了解了上面的约定之后,我们就开始定义我们自己的中间件Class。
我们需要一个流程图来理清逻辑思路,以便于写代码的时候思路更加的清晰。

平台有一个要求就是,用户在我们子系统退出之后,要调用平台的一个接口通知他们,他们要做一些后续的业务。
OK,开始撸码。
- 首先创建一个
PlatformAuthoricationMiddleware,它继承于Microsoft.AspNetCore.Authentication下的类AuthenticationMiddleware,由于AuthenticationMiddleware已经实现了Invoke功能,所以我们只需要重写(override)它里面的一些方法就可以了。等等,我们好像还需要一些配置,比如流程图中的ReturnUrl,平台的Cookie的Key值,平台验证用户合法性的接口地址等参数。 - 建立一个Options类进行配置的设置,我们取名字为:
PlatformAuthenticationOptions,继承AuthenticationOptions,并且实现掉IOptions<T>接口,这样子就能在Startup中直接配置了。 - 我们只需要重写
AuthenticationMiddleware中的CreateHandler方法就行了,在Handler中可以实现掉我们中间件的功能。 - 然后创建一个处理的Handler类,取名为
PlatformAuthenticationHandler,继承于AuthenticationHandler<TOptions>用来处理请求中的调用。
至此,我们的核心需要的类已经建立完了,剩下的就是填充代码。
- 在
PlatformAuthenticationHandler中重写HandleAuthenticateAsync()方法 , 进行主流程的控制。 - 在
PlatformAuthenticationHandler中重写FinishResponseAsync()方法,进行Session的存储操作。 - 在
PlatformAuthenticationHandler中重写HandleSignOutAsync()方法,进行登出的控制,因为用户登出之后我们要通知平台做一些其他操作。 - 在
PlatformAuthenticationHandler中重写HandleUnauthorizedAsync()方法,进行未认证操作。
最后,我们需要一个扩展类来把我们的中间件以扩展方法注册到管道当中去 。
public static class MiddlewareExtensions
{
public static IApplicationBuilder UsePlatformAuthentication(this IApplicationBuilder app) {
if (app == null) {
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<PlatformAuthenticationMiddleware>();
}
public static IApplicationBuilder UsePlatformAuthentication(this IApplicationBuilder app, CookieAuthenticationOptions options) {
if (app == null) {
throw new ArgumentNullException(nameof(app));
}
if (options == null) {
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<PlatformAuthenticationMiddleware>(Options.Create(options));
}
}
在Startup中就是app.UsePlatformAuthentication()
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
//注册PlatformAuthentication中间件
app.UsePlatformAuthentication(new PlatformAuthenticationOptions() {
UserSessionStore = new UserSessionStore(),
});
app.UseMvc();
}
现在,我们的中间件核心业务流程的实现已经出来了,我就不大篇幅的粘贴代码了,会影响阅读,感兴趣具体实现的朋友可以去下面的地址查看代码,有具体流程的注释。
示例源码:
https://github.com/yuleyule66/PlatformAuthMiddleware
net core 中间件详解及项目实战的更多相关文章
- ASP.NET Core 中间件详解及项目实战
前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World,如果你觉得本篇文章 ...
- [转]ASP.NET Core 中间件详解及项目实战
本文转自:http://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际 ...
- 【转载】ASP.NET Core 中间件详解及项目实战
前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World,如果你觉得本篇文章 ...
- Django 2.0 学习(20):Django 中间件详解
Django 中间件详解 Django中间件 在Django中,中间件(middleware)其实就是一个类,在请求到来和结束后,Django会根据自己的规则在合适的时机执行中间件中相应的方法. 1. ...
- Git详解之一 Git实战
Git详解之一 Git实战 入门 本章介绍开始使用 Git 前的相关知识.我们会先了解一些版本控制工具的历史背景,然后试着让 Git 在你的系统上跑起来,直到最后配置好,可以正常开始开发工作.读完本章 ...
- 3.awk数组详解及企业实战案例
awk数组详解及企业实战案例 3.打印数组: [root@nfs-server test]# awk 'BEGIN{array[1]="zhurui";array[2]=" ...
- 【转】段错误调试神器 - Core Dump详解
from:http://www.embeddedlinux.org.cn/html/jishuzixun/201307/08-2594.html 段错误调试神器 - Core Dump详解 来源:互联 ...
- (转)awk数组详解及企业实战案例
awk数组详解及企业实战案例 原文:http://www.cnblogs.com/hackerer/p/5365967.html#_label03.打印数组:1. [root@nfs-server t ...
- Django中间件详解
Django中间件详解 中间件位置 WSGI 主要负责的就是负责和浏览器和应用之家沟通的桥梁 浏览器发送过来一个http请求,WSGI负责解包,并封装成能够给APP使用的environ,当app数据返 ...
随机推荐
- JS 获取星期几的四种写法
今天是星期几的4种JS代码写法,有需要的朋友可以参考一下 第一种写法 复制代码代码如下: var str = ""; var week = new Date().getDay() ...
- vim插件管理之Vundle
Vim是一个类似于Vi的著名的功能强大.高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性.正是由于其可定制的特性, 许许多多的Vim插件便诞生了.管理这些插件又成为我们最为头疼的问题,最近无 ...
- hdu 2814 快速求欧拉函数
/** 大意: 求[a,b] 之间 phi(a) + phi(a+1)...+ phi(b): 思路: 快速求欧拉函数 **/ #include <iostream> #include & ...
- 面向对象程序设计-C++ Finial exam review NOTES【第十六次上课笔记】
写在前面: 我记得也不全,如果有记录的更全的同学可以留言,我会添加哒 :) 常量 内敛函数 为什么需要内敛函数 内敛函数适用于什么场合 内敛函数本身,最大优点是,避免了真正函数调用的开销 因为普通函数 ...
- 7,C++ public, protected, private 继承的区别
在某处看到一张图,简单明了的说明了三者的关系,很是佩服,遂记录下来. //公有继承 对象访问 成员访问 public --> public Y Y protected --> protec ...
- 转:requirejs打包压缩r.js使用示例
为了应对日益复杂,大规模的JavaScript开发.我们化整为零,化繁为简.将复杂的逻辑划分一个个小单元,各个击破.这时一个项目可能会有几十个甚至上百个JS文件,每个文件为一个模块单元.如果上线时都是 ...
- 《Clean Code》重点内容总结
读书笔记请见Github博客:http://wuxichen.github.io/Myblog/reading/2014/10/06/CleanCode.html
- vs提示“当前不会命中断点,源代码与原始版本不同”的一种解决办法
将出问题的cpp文件用notepad打开,另存为‘unicode’类型,覆盖源文件即可
- CentOS中使用shell的命令补全
习惯debian的用户都知道shell中的自动补全功能非常实用,其中在CentOS中也可以有同样的功能. 只需要安装 bash-completion 包即可. rpm -ivh http://www. ...
- Android GPS应用:临近警告
前面介绍过LocationManager有一个addProximityAlert(double latitude,double longitude,float radius,long expirati ...