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种方式可以在管道中注册"中间件"

  1. app.Use()IApplicationBuilder接口原生提供,注册等都用它。
  2. app.Run() ,是一个扩展方法,它需要一个RequestDelegate委托,里面包含了Http的上下文信息,没有next参数,因为它总是在管道最后一步执行。
  3. 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>用来处理请求中的调用。

至此,我们的核心需要的类已经建立完了,剩下的就是填充代码。

  1. PlatformAuthenticationHandler中重写HandleAuthenticateAsync()方法 , 进行主流程的控制。
  2. PlatformAuthenticationHandler中重写FinishResponseAsync()方法,进行Session的存储操作。
  3. PlatformAuthenticationHandler中重写HandleSignOutAsync()方法,进行登出的控制,因为用户登出之后我们要通知平台做一些其他操作。
  4. 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

时间: 2024-12-24 21:53:20

net core 中间件详解及项目实战的相关文章

ASP.NET Core 中间件详解及项目实战

前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World,如果你觉得本篇文章对你有用的话,不妨点个[推荐]. 目录 中间件(Middleware)的作用 中间件的运行方式 中间件(Middleware)和过滤器(Filter)的区别 什么情况我们需要中间件 怎么样自定义自己的中间件 中间件(Middleware)的作用 我们知道,任何的一个web框架都是把http请求封装成

linux移植u-boot(一)——U-Boot详解+自定义命令实战

linux移植u-boot(一)--U-Boot详解+自定义命令实战 2015-02-07 一.Bootloader ????简单地说:Bootloader主要功能就是 在系统上电时开始执行,初始化硬件和设备,准备好软件环境,最后调用操作系统. ????具体的包含:关闭你看门狗WATCHDOG,改变系统时钟,初始化存储控制器 ,将操作系统内核代码复制到内存中去运行. ????为了开发方便,可以增加网络功能,从PC上通过串口或者网络下载文件,烧写文件,将flash上的内核代码解压后运行等. Boo

下载Zookeeper从入门到精通(开发详解,案例实战,Web界面监控)

ZooKeeper是Hadoop的开源子项目(Google Chubby的开源实现),它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护.命名服务.分布式同步.组服务等. Zookeeper的Fast Fail 和 Leader选举特性大大增强了分布式集群的稳定和健壮性,并且解决了Master/Slave模式的单点故障重大隐患,这是越来越多的分布式产品如HBase.Storm(流计算).S4(流计算)等强依赖Zookeeper的原因. Zookeeper从入门到精通(开发详解,案

【转】段错误调试神器 - Core Dump详解

from:http://www.embeddedlinux.org.cn/html/jishuzixun/201307/08-2594.html 段错误调试神器 - Core Dump详解 来源:互联网 作者:Alex 时间:2013-07-08 Tag:Linux   点击: 11670 一.前言: 有的程序可以通过编译, 但在运行时会出现Segment fault(段错误). 这通常都是指针错误引起的. 但这不像编译错误一样会提示到文件某一行, 而是没有任何信息, 使得我们的调试变得困难起来

CSS3属性选择器详解 及 双色球实战开发

在前面的章节中,我们了解了,可以使用行内样式,ID选择器,类选择器,以及标签选择器来给一个元素应用样式. 如果我们想给定义了那些都定义了某一个属性的元素应用样式,这个时候我们该怎么做呢? 这一节中,我将使用 双色球案例 和 文档类型提示图标案例 来引入和应用属性选择器. 双色球案例: 大家都知道,双色球共有7个球,6个红球,1个蓝球.首先我们先在页面上面定义7个span标签: <!DOCTYPE html> <html> <head> <meta charset=

MySql日志详解及应用实战

1.mysql主从有主-从.主-主形式 其中主从形式,主负责写入,从负责读取,主数据库如果挂掉则将另一台从数据库提升为主,更换主库速度较慢 主主形式用于搜索引擎,与主从的区别为,当有数据写入时,如果写入数据库A成功则默认A为主库,一旦写入A异常则立即更换B库写入,此时B库就提升为主库,与主从形式相比,因为不存在严格的主从关系,所以更换主库速度快.缺点是因为两台数据库都可以变更数据,容易导致数据紊乱(主要表现在自增主键). 多台写入导致自增主键紊乱可以通过 修改自增主键自增量(如有2台数据库,可以

(转)awk数组详解及企业实战案例

awk数组详解及企业实战案例 原文:http://www.cnblogs.com/hackerer/p/5365967.html#_label03.打印数组:1. [[email protected] test]# awk 'BEGIN{array[1]="zhurui";array[2]="zhuzhu";for(key in array) print key,array[key]}'2. 1 zhurui3. 2 zhuzhu4. [[email protect

Zookeeper从入门到精通(开发详解,案例实战,Web界面监控)

ZooKeeper是Hadoop的开源子项目(Google Chubby的开源实现),它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护.命名服务.分布式同步.组服务等. Zookeeper的Fast Fail 和 Leader选举特性大大增强了分布式集群的稳定和健壮性,并且解决了Master/Slave模式的单点故障重大隐患,这是越来越多的分布式产品如HBase.Storm(流计算).S4(流计算)等强依赖Zookeeper的原因. Zookeeper在分布式集群(Hadoop

iOS Core Animation详解(四)AutoLayout中的动画

原创blog,转载请注明出处 blog.csdn.net/hello_hwc 欢迎关注我的iOS SDK详解专栏 http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html 前言:AutoLayout定义了View的位置,也就是说,在Auto Layout的工程里,如果不修改约束本身,在视图重新绘制的时候,还会回到最开始的位置.AutoLayout中的动画与视图的位置和大小有关. 先看看效果 实现过程 在Storyboard上拖拽一