ASP.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
本文地址:http://www.cnblogs.com/savorboard/p/5586229.html
作者博客:Savorboard
欢迎转载,请保留出处
ASP.NET Core 中间件详解及项目实战的更多相关文章
- [转]ASP.NET Core 中间件详解及项目实战
本文转自:http://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际 ...
- 【转载】ASP.NET Core 中间件详解及项目实战
前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World,如果你觉得本篇文章 ...
- net core 中间件详解及项目实战
net core 中间件详解及项目实战 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的H ...
- asp.net core 中间件粗解
中间件 中间件在asp.net core中非常重要,它用来处理httpcontext.而httpcontext封装了请求和响应.也就是说,中间件是用来处理请求和响应的. 本质上,中间件被封装到了IAp ...
- 第十节:Asp.Net Core 配置详解和选项模式
一. 各种文件的读取 1.说明 在.Net Core中,各种配置文件的读取都需要依赖[Microsoft.Extensions.Configuration]程序集,当然在Asp.Net Core中已经 ...
- ASP.NET Core管道详解[2]: HttpContext本质论
ASP.NET Core请求处理管道由一个服务器和一组有序排列的中间件构成,所有中间件针对请求的处理都在通过HttpContext对象表示的上下文中进行.由于应用程序总是利用服务器来完成对请求的接收和 ...
- ASP.NET Core管道详解[3]: Pipeline = IServer + IHttpApplication
ASP.NET Core的请求处理管道由一个服务器和一组中间件构成,但对于面向传输层的服务器来说,它其实没有中间件的概念.当服务器接收到请求之后,会将该请求分发给一个处理器进行处理,对服务器而言,这个 ...
- ASP.NET Core管道详解[6]: ASP.NET Core应用是如何启动的?[下篇]
要承载一个ASP.NET Core应用,只需要将GenericWebHostService服务注册到承载系统中即可.但GenericWebHostService服务具有针对其他一系列服务的依赖,所以在 ...
- asp.net core 中间件应用
中间件是一种装配到应用管道以处理请求和响应的软件. 每个组件: 选择是否将请求传递到管道中的下一个组件. 可在调用管道中的下一个组件前后执行工作. 请求委托(Request delegates)用于生 ...
随机推荐
- 分布式系列文章——Paxos算法原理与推导
Paxos算法在分布式领域具有非常重要的地位.但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难. 网上有很多讲解Paxos算法的文章,但是质量参差不齐.看了很多关于Paxos的资 ...
- 百度推出新技术 MIP,网页加载更快,广告呢?
我们在2016年年初推出了MIP,帮助移动页面加速(原理).内测数据表明,MIP页面在1s内加载完成.现在已经有十多家网站加入MIP项目,有更多的网站正在加入中.在我们收到的反馈中,大部分都提到了广告 ...
- 一看就懂的ReactJs入门教程-精华版
现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我,下面来跟我一起领 ...
- 实现一个类 RequireJS 的模块加载器 (二)
2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...
- 小兔JS教程(四)-- 彻底攻略JS数组
在开始本章之前,先给出上一节的答案,参考答案地址: http://www.xiaotublog.com/demo.html?path=homework/03/index2 1.JS数组的三大特性 在J ...
- JS继承之借用构造函数继承和组合继承
根据少一点套路,多一点真诚这个原则,继续学习. 借用构造函数继承 在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术( ...
- Node.js入门(一)
一.Node.js本质上是js的运行环境. 二.可以解析js代码(没有浏览器安全级的限制): 提供系统级的API:1.文件的读写 2.进程的管理 3.网络通信 三.可以关注的四个网站: 1.https ...
- 常用 meta 整理
<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 --> <meta name="HandheldFriendly" con ...
- ASP.NET Aries JSAPI 文档说明:AR.DataGrid
AR.DataGrid 文档 用法: <body> <table id="dg"></table> </body> </htm ...
- 分享在Linux下使用OSGi.NET插件框架快速实现一个分布式服务集群的方法
在这篇文章我分享了如何使用分层与模块化的方法来设计一个分布式服务集群.这个分布式服务集群是基于DynamicProxy.WCF和OSGi.NET插件框架实现的.我将从设计思路.目标和实现三方面来描述. ...