zoukankan      html  css  js  c++  java
  • 创建自定义的Middleware中间件

    创建自定义的Middleware中间件

    经过前2篇文章的介绍,相信大家已经对OWIN和Katana有了基本的了解,那么这篇文章我将继续OWIN和Katana之旅——创建自定义的Middleware中间件。

    何为Middleware中间件

    Middleware中间件从功能上可以理解为用来处理Http请求,当Server将Http请求封装成符合OWIN规范的字典后,交由Middleware去处理,一般情况下,Pipeline中的Middleware以链式的形式处理Http请求,即每一个Middleware都是最小的模块化,彼此独立、高效。

    从语法上理解Middleware的话,他是一个应用程序委托(Func<IDictionary<stringobject>Task>)的实例,通过使用IAppBuilder 接口的Use或者Run方法将一个Middleware插入到Pipeline中,不同的是使用Run方法不需要引用下一个Middleware,即他是Pipeline中最后的处理元素。

    使用Inline方式注册Middleware

    使用Use方法可以将一个Middleware插入到Pipeline中,值得注意的是需要传入下一个Middleware的引用,代码如下所示:

    1. app.Use(new Func<Func<IDictionary<string, object>, Task>/*Next*/,
    2.              Func<IDictionary<string, object>/*Environment Dictionary*/, Task>>(next => async env =>
    3.              {
    4.                  string before = "Middleware1--Before(inline)"+Environment.NewLine;
    5.                  string after = "Middleware1--After(inline)"+Environment.NewLine;
    6.                  var response = env["owin.ResponseBody"] as Stream;
    7.                  await response.WriteAsync(Encoding.UTF8.GetBytes(before), 0, before.Length);
    8.                  await next.Invoke(env);
    9.                  await response.WriteAsync(Encoding.UTF8.GetBytes(after), 0, after.Length);
    10.          }));

    上述代码中,实例化了一个委托,它需要传入下一个Pipeline中的Middleware引用同时返回一个新的Middleware并插入到Pipeline中。因为是异步的,所以别忘了async、await关键字。

    使用Inline+ AppFunc方式注册Middleware

    为了简化书写,我为应用程序委托(Func<IDictionary<stringobject>Task>)类型创建了别名AppFunc:

    1. using AppFunc=Func<IDictionary<string,object>/*Environment Dictionary*/,Task/*Task*/>;

    所以又可以使用如下方式来讲Middleware添加到Pipeline中:

    1. app.Use(new Func<AppFunc, AppFunc>(next => async env =>
    2. {
    3.     string before = " Middleware2--Before(inline+AppFunc)" + Environment.NewLine;
    4.     string after = " Middleware2--After(inline+AppFunc)" + Environment.NewLine;
    5.     var response = env["owin.ResponseBody"] as Stream;
    6.     await response.WriteAsync(Encoding.UTF8.GetBytes(before), 0, before.Length);
    7.     await next.Invoke(env);
    8.     await response.WriteAsync(Encoding.UTF8.GetBytes(after), 0, after.Length);
    9. }));

    考虑到业务逻辑的增长,有必要将Lambda表达式中的处理逻辑给分离开来,所以对上述代码稍作修改,提取到一个名为Invoke的方法内:

    1. app.Use(new Func<AppFunc, AppFunc>(next => env => Invoke(next, env)));
    2. private async Task Invoke(Func<IDictionary<string, object>, Task> next, IDictionary<string,object> env)
    3.         {
    4.             var response = env["owin.ResponseBody"] as Stream;
    5.             string pre = " Middleware 3 - Before (inline+AppFunc+Invoke)" + Environment.NewLine;
    6.             string post = " Middleware 3 - After (inline+AppFunc+Invoke)" + Environment.NewLine;
    7.             await response.WriteAsync(Encoding.UTF8.GetBytes(pre), 0, pre.Length);
    8.             await next.Invoke(env);
    9.             await response.WriteAsync(Encoding.UTF8.GetBytes(post), 0, post.Length);
    10.         }

    虽然将业务逻辑抽取到一个方法中,但Inline这种模式对于复杂的Middleware还是显得不够简洁、易懂。我们更倾向于创建一个单独的类来表示。

    定义原生Middleware类的形式来注册Middleware

    如果你只想简单的跟踪一下请求,使用Inline也是可行的,但对于复杂的Middleware,我倾向于创建一个单独的类,如下所示:

    1. public class RawMiddleware
    2.   {
    3.       private readonly AppFunc _next;
    4.       public RawMiddleware(AppFunc next)
    5.       {
    6.           this._next = next;
    7.       }
    8.       public async Task Invoke(IDictionary<string,object> env )
    9.       {
    10.           var response = env["owin.ResponseBody"] as Stream;
    11.           string pre = " Middleware 4 - Before (RawMiddleware)" + Environment.NewLine;
    12.           string post = " Middleware 4 - After (RawMiddleware) " + Environment.NewLine;
    13.           await response.WriteAsync(Encoding.UTF8.GetBytes(pre), 0, pre.Length);
    14.           await _next.Invoke(env);
    15.           await response.WriteAsync(Encoding.UTF8.GetBytes(post), 0, post.Length);
    16.       }
    17.   }

    最后,依旧是通过Use方法来将Middleware添加到Pipeline中:

    1. //两者方式皆可
    2. //app.Use<RawMiddleware>();
    3. app.Use(typeof (RawMiddleware));

    上述代码中,IAppBuilder实例的Use方法添加Middleware至Pipeline与Inline方式有很大不同,它接受一个Type而非Lambda表达式。在这种情形下,创建了一个Middleware类型的实例,并将Pipeline中下一个Middleware传递到构造函数中,最后当Middleware被执行时调用Invoke方法。

    注意Middleware是基于约定的形式定义的,需要满足如下条件:

    • 构造函数的第一个参数必须是Pipeline中下一个Middleware
    • 必须包含一个Invoke方法,它接收Owin环境字典,并返回Task

    使用Katana Helper来注册Middleware

    程序集Microsoft.Owin包含了Katana为我们提供的Helper,通过他,可以简化我们的开发,比如IOwinContext封装了Owin的环境字典,强类型对象可以通过属性的形式获取相关数据,同时为IAppBuilder提供了丰富的扩展方法来简化Middleware的注册,如下所示:

    1. app.Use(async (context, next) =>
    2.            {
    3.                await context.Response.WriteAsync(" Middleware 5--Befone(inline+katana helper)"+Environment.NewLine);
    4.                await next();
    5.                await context.Response.WriteAsync(" Middleware 5--After(inline+katana helper)"+Environment.NewLine);
    6.            });

    当然我们也可以定义一个Middleware类并继承OwinMiddleware,如下所示:

    1. public class MyMiddleware : OwinMiddleware
    2.    {
    3.        public MyMiddleware(OwinMiddleware next)
    4.            : base(next)
    5.        {
    6.  
    7.        }
    8.        public override async Task Invoke(IOwinContext context)
    9.        {
    10.            await context.Response.WriteAsync(" Middleware 6 - Before (Katana helped middleware class)"+Environment.NewLine);
    11.            await this.Next.Invoke(context);
    12.            await context.Response.WriteAsync(" Middleware 6 - After (Katana helped middleware class)"+Environment.NewLine);
    13.        }
    14.    }

    然后将其添加到Pipeline中:

    1. app.Use<MyMiddleware>();

    Middleware的执行顺序

    在完成上面Middleware注册之后,在Configuration方法的最后添加最后一个的Middleware中间件,注意它并不需要对下一个Middleware的引用了,我们可以使用Run方法来完成注册:

    1. app.Run(context => context.Response.WriteAsync(" Hello World"+Environment.NewLine));

    值得注意的是,Pipeline中Middleware处理Http Request顺序同注册顺序保持一致,即和Configuration方法中书写的顺序保持一致,Response顺序则正好相反,如下图所示:

    最后,运行程序,查看具体的输出结果是否和我们分析的保持一致:

    小结

    在这篇文章中,我为大家讲解了自定义Middleware的创建,Katana为我们提供了非常多的方式来创建和注册Middleware,在下一篇文章中,我将继续OWIN和Katana之旅,探索Katana和其他Web Framework的集成。

    本博客为木宛城主原创,基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名木宛城主(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。
  • 相关阅读:
    在IE和Firfox获取keycode
    using global variable in android extends application
    using Broadcast Receivers to listen outgoing call in android note
    help me!virtual keyboard issue
    using iscroll.js and iscroll jquery plugin in android webview to scroll div and ajax load data.
    javascript:jquery.history.js使用方法
    【CSS核心概念】弹性盒子布局
    【Canvas学习笔记】基础篇(二)
    【JS核心概念】数据类型以及判断方法
    【问题记录】ElementUI上传组件使用beforeupload钩子校验失败时的问题处理
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4625893.html
Copyright © 2011-2022 走看看