在上篇文章主要介绍了DotNetCore项目情况,本篇文章是咱们在开发本身的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深刻使用了,不是简单的Hello World,若是你以为本篇文章对你有用的话,不妨点个【推荐】。html
咱们知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是通过管道的一系列操做,最终到达咱们写的代码中。那么中间件就是在应用程序管道中的一个组件,用来拦截请求过程进行一些其余处理和响应。中间件能够有不少个,每个中间件均可以对管道中的请求进行拦截,它能够决定是否将请求转移给下一个中间件。git
asp.net core 提供了IApplicationBuilder
接口来让把中间件注册到asp.net的管道请求当中去,中间件是一个典型的AOP应用。 下面是一个微软官方的一个中间件管道请求图:github
能够看到,每个中间件都均可以在请求以前和以后进行操做。请求处理完成以后传递给下一个请求。web
默认状况下,中间件的执行顺序根据Startup.cs
文件中,在public void Configure(IApplicationBuilder app){}
方法中注册的前后顺序执行。
大概有3种方式能够在管道中注册"中间件"app
app.Use()
,IApplicationBuilder
接口原生提供,注册等都用它。app.Run()
,是一个扩展方法,它须要一个RequestDelegate
委托,里面包含了Http的上下文信息,没有next参数,由于它老是在管道最后一步执行。app.Map()
,也是一个扩展方法,相似于MVC的路由,用途通常是一些特殊请求路径的处理。如:www.example.com/token 等。上面的Run,Map内部也是调用的Use,算是对IApplicationBuilder接口扩充,若是你以为名字都不够准确,那么下面这个扩展方法就是正宗的注册中间件的了,也是功能最强大的。
app.UseMiddleware<>()
,没错,就是这个了。 为何说功能强大呢?是由于它不但提供了注册中间件的功能,还提供了依赖注入(DI)的功能,之后大部分状况就用它了。框架
熟悉MVC框架的同窗应该知道,MVC也提供了5大过滤器供咱们用来处理请求先后须要执行的代码。分别是AuthenticationFilter
,AuthorizationFilter
,ActionFilter
,ExceptionFilter
,ResultFilter
。asp.net
根据描述,能够看出中间件和过滤器的功能相似,那么他们有什么区别?为何又要搞一个中间件呢?
其实,过滤器和中间件他们的关注点是不同的,也就是说职责不同,干的事情就不同。async
举个栗子,中间件像是
埃辛诺斯战刃
,过滤器像是巨龙之怒,泰蕾苟萨的寄魂杖
,你一个战士拿着巨龙之怒,泰蕾苟萨的寄魂杖
去战场杀人,虽然都有伤害,可是你拿着法杖伤害低不说,还减属性啊。ide
同做为两个AOP利器,过滤器更贴合业务,它关注于应用程序自己,好比你看ActionFilter
和 ResultFilter
,它都直接和你的Action,ActionResult交互了,是否是离你很近的感受,那我有一些好比对个人输出结果进行格式化啦,对个人请求的ViewModel进行数据验证啦,确定就是用Filter无疑了。它是MVC的一部分,它能够拦截到你Action上下文的一些信息,而中间件是没有这个能力的。ui
那么,什么时候使用中间件呢?个人理解是在咱们的应用程序当中和业务关系不大的一些须要在管道中作的事情可使用,好比身份验证,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值,平台验证用户合法性的接口地址等参数。PlatformAuthenticationOptions
,继承AuthenticationOptions
,而且实现掉IOptions<T>
接口,这样子就能在Startup中直接配置了。AuthenticationMiddleware
中的CreateHandler
方法就好了,在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
本文地址:http://www.cnblogs.com/savorboard/p/5586229.html
做者博客:Savorboard 欢迎转载,请保留出处