博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Nancy之Pipelines三兄弟(Before After OnError)
阅读量:5736 次
发布时间:2019-06-18

本文共 9245 字,大约阅读时间需要 30 分钟。

原文:

一、简单描述

Before:如果返回null,拦截器将主动权转给路由;如果返回Response对象,则路由不起作用。

After : 没有返回值,可以在这里修改或替换当前的Response。

OnError : 返回值与Before相似,引发的错误或异常时的控制代码可以写在这里。

这三兄弟的大致作用,看名字,也可以这样简单的理解:

Before:处理之前要干的事。(返回null,继续处理;返回Response对象,不再做要干的那件事,换做Response对象要干的事)

After : 处理之后要干的事。

OnError : 处理出错了要干的事。

这三兄弟在NancyModule中的定义如下

1 public AfterPipeline After { get; set; } 2 public BeforePipeline Before { get; set; }3 public ErrorPipeline OnError { get; set; }

而这三个Pipeline分别继承了 

AsyncNamedPipelineBase<TAsyncDelegate, TSyncDelegate>和NamedPipelineBase<TDelegate>

所以与他们有关的就主要包含在5个类中!具体的放在最后来看一下!

 

二、简单用法

我们可以在Module中直接使用Before/After/OnError这三个

也可以在Bootstrapper中重写RequestStartup或者ApplicationStartup来实现

当然也可以自定义,只要实现IRequestStartup或者IApplicationStartup接口也可以完成相应的工作

 

下面我们就分别来说明一下

用法一:直接在Module中使用

定义一个BaseModule,具体如下:

1     public class BaseModule : NancyModule 2     { 3         public BaseModule() 4         { 5             //写法一 6             Before += ctx => { 7                 System.Diagnostics.Debug.WriteLine("BaseModule---Before"); 8                 return null; 9             };10             After += ctx => {11                 System.Diagnostics.Debug.WriteLine("BaseModule---After");12             };13             OnError += (ctx, ex) => {14                 System.Diagnostics.Debug.WriteLine("BaseModule---OnError");15                 System.Diagnostics.Debug.WriteLine(ex.ToString());16                 return null;17             };18             //写法二19             //Before += MyBefore;20             //After += MyAfter;21             //OnError += MyOnError;22         }23         private Response MyBefore(NancyContext ctx)24         {25             System.Diagnostics.Debug.WriteLine("BaseModule---Before----写法二");26             return null;27         }28         private void MyAfter(NancyContext ctx)29         {30             System.Diagnostics.Debug.WriteLine("BaseModule---After----写法二");31         }32         private Response MyOnError(NancyContext ctx, Exception ex)33         {34             System.Diagnostics.Debug.WriteLine("BaseModule---OnError----写法二");35             System.Diagnostics.Debug.WriteLine(ex.ToString());36             return null;37         }38     }

 

在BaseModule中,用了两种不同的形式来对Before、After、OnError进行处理,

都只是打印出一些简单的信息,看这些输出的信息,可以帮助理解内部执行的顺序!

可以看到,Before和OnError是Response类型的,After是void类型的

在这三兄弟的具体处理中,要根据实际情况来定(当然,你想就打印出一些东西也没问题,毕竟我们还是可以把这些东西写进日记嘛)!

下面定义一个HomeModule,具体如下:

1     public class HomeModule : BaseModule2     {3         public HomeModule()4         {5             Get["/"] = _ => "Catcher Wong";6             Get["/err"] = _ => { throw new Exception("there're some errors"); };7         }8     }

其中,当我们访问http://localhost:port时,会显示我们的文字,访问http://localhost:port/err时,会抛出我们设定异常!

运行起来,看看我们的Output(输出)窗口

这是访问http://localhost:port时的情况

 

访问http://localhost:port/err时的情况

出现异常后并没有去执行After!!执行完OnError之后就结束了。

 

同样的,用写法二也是如此!

基本一致的效果。

用法二:在bootstrapper中重写RequestStartup或者ApplicationStartup

 

先来看看重写RequestStartup

1     public class Bootstrapper : DefaultNancyBootstrapper 2     { 3         protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context) 4         { 5             base.RequestStartup(container, pipelines, context); 6             pipelines.BeforeRequest += ctx => { 7                 System.Diagnostics.Debug.WriteLine("Boorstrapper---RequestStartup---Before"); 8                 return null; 9             };10             pipelines.AfterRequest += ctx => {11                 System.Diagnostics.Debug.WriteLine("Boorstrapper---RequestStartup---After");12             };13             pipelines.OnError += (ctx,ex) => {14                 System.Diagnostics.Debug.WriteLine("Boorstrapper---RequestStartup---OnError");15                 System.Diagnostics.Debug.WriteLine(ex.ToString());16                 return null;17             };18         }       19     }

 

我们同样是输出相应的信息,运行前,把我们BaseModule中“三兄弟”的注释掉

再来看看重写ApplicationStartup

1      public class Bootstrapper : DefaultNancyBootstrapper 2     { 3         protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) 4         { 5             base.ApplicationStartup(container, pipelines); 6             pipelines.BeforeRequest += MyBeforeRequest; 7             pipelines.AfterRequest += MyAfterRequest; 8             pipelines.OnError += MyOnErroe; 9         }10         private Response MyBeforeRequest(NancyContext ctx)11         {12             System.Diagnostics.Debug.WriteLine("Boorstrapper---ApplicationStartup---Before");13             return null;14         }15         private void MyAfterRequest(NancyContext ctx)16         {17             System.Diagnostics.Debug.WriteLine("Boorstrapper---ApplicationStartup---After");18         }19         private Response MyOnErroe(NancyContext ctx, Exception ex)20         {21             System.Diagnostics.Debug.WriteLine("Boorstrapper---ApplicationStartup---OnError");22             System.Diagnostics.Debug.WriteLine(ex.ToString());23             return null;24         }25     }

 

我们同样是输出相应的信息,运行前,把我们BaseModule和RequestStartup中“三兄弟”的注释掉

 

用法三:自定义用法(Nancy中有很多东西可以自定义,这个很灵活,很nice!)

下面来看看自定就要怎么使用!

1     public class CustomRequest : IApplicationStartup 2     {        3         public void Initialize(IPipelines pipelines) 4         { 5             pipelines.BeforeRequest.AddItemToEndOfPipeline(ctx => 6             { 7                 System.Diagnostics.Debug.WriteLine("CustomRequest---IApplicationStartup---Before");                 8                 return null; 9             });10             pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>11             {12                 System.Diagnostics.Debug.WriteLine("CustomRequest---IApplicationStartup---After");13             });14             pipelines.OnError.AddItemToEndOfPipeline((ctx, ex) =>15             {16                 System.Diagnostics.Debug.WriteLine("CustomRequest---IApplicationStartup---OnError");17                 System.Diagnostics.Debug.WriteLine(ex.ToString());18                 return null;19             });20         }21     }

我们自定义一个CustomRequest让它实现IApplicationStartup接口即可!

剩下的就是实现Before、After、OnError的处理!!

把之前的相关处理注释掉,运行。

效果如下:

 
前面提到的,都是每种用法单独的运行执行效果,那么,每种用法的执行顺序呢?下面来看看,把所有的注释去掉,运行
 
 

现在是否很清晰呢?

Before 的执行顺序  IApplicationStartup > ApplicationStartup > RequestStartup > BaseModule

OnError的执行顺序 BaseModule > IApplicationStartup > ApplicationStartup > RequestStartup
 
再来看看After的执行顺序

与OnError的处理顺序一样!!

三、内部实现的简单分析

前面也提到了,这三兄弟的实现主要有这几个类

BeforePipeline、AfterPipeline、ErrorPipeline以及抽象类NamedPipelineBase、AsyncNamedPipelineBase

NancyModule中也有相应的Before、After、OnError定义!

先来看看BeforePipeline吧

BeforePipeline是实现了AsyncNamedPipelineBase这个抽象类

里面有用到 implicit operator ,不熟悉的可以参考

有一个重写的Wrap方法,用于把同步的包装成异步的形式

1         protected override PipelineItem
>> Wrap(PipelineItem
> pipelineItem) 2 { 3 var syncDelegate = pipelineItem.Delegate; 4 Func
> asyncDelegate = (ctx, ct) => 5 { 6 var tcs = new TaskCompletionSource
(); 7 try 8 { 9 var result = syncDelegate.Invoke(ctx);10 tcs.SetResult(result);11 }12 catch (Exception e)13 {14 tcs.SetException(e);15 }16 return tcs.Task;17 };18 return new PipelineItem
>>(pipelineItem.Name, asyncDelegate);19 }

其他的大致都可以总结成下面这句代码:

pipeline.AddItemToEndOfPipeline(xxxx);  

把xxxx添加到管道中的末尾去。

同样的,AfterPipeline与ErrorPipeline也是相类似的,

不同的是ErrorPipeline实现的是NamedPipelineBase这个抽象类,

没有那个Wrap方法,多了一个dynamic的Invoke方法

1         public dynamic Invoke(NancyContext context, Exception ex) 2         { 3             dynamic returnValue = null; 4             using (var enumerator = this.PipelineDelegates.GetEnumerator()) 5             { 6                 while (returnValue == null && enumerator.MoveNext()) 7                 { 8                     returnValue = enumerator.Current.Invoke(context, ex); 9                 }10             }11             return returnValue;12         }

 

 

这个Invoke方法的作用是:依次调用每个管道项目,直到有管道项目被返回或者所有管道项目都已经被调用了!

两个NamePipelineBase(同步和异步)都定义了一个pipelineItems(要执行的管道项目集合)

还有众多虚方法!!大部分是插入的,还有一个删除的。

其中插入可分为在Pipeline的开始和结尾插入,以及是否要替换已存在的同名的Pipeline

下面的是比较重要的一个方法InsertItemAtPipelineIndex

同步的

1          public virtual void InsertItemAtPipelineIndex(int index, PipelineItem
item, bool replaceInPlace = false)2 {3 var existingIndex = this.RemoveByName(item.Name);4 var newIndex = (replaceInPlace && existingIndex != -1) ? existingIndex : index;5 this.pipelineItems.Insert(newIndex, item);6 }

异步的

1         public virtual void InsertItemAtPipelineIndex(int index, PipelineItem
item, bool replaceInPlace = false)2 { 3 var existingIndex = this.RemoveByName(item.Name);4 var newIndex = (replaceInPlace && existingIndex != -1) ? existingIndex : index;5 this.pipelineItems.Insert(newIndex, item);6 }

 

这个方法的主要作用是将item插入到Pipeline的指定位置!(同步和异步的都有相应的实现!!不同的是item的类型而已!)
 
内部实现,简单点的说法就是:就把我们写的东西添加进Pipline去处理
 

 最后来看看我们在Bootstrapper和自定义用到的IPipelines

1     public interface IPipelines2     {   3         BeforePipeline BeforeRequest { get; set; }     4         AfterPipeline AfterRequest { get; set; }5         ErrorPipeline OnError { get; set; }6     }

十分简单的定义!

 

转载地址:http://zdgwx.baihongyu.com/

你可能感兴趣的文章
解决cacti监控windows网卡带有中文
查看>>
梁念坚:“云计算”福音
查看>>
管理软件的飞跃:像用自来水一样用
查看>>
四块固态硬盘联合刷新PCMark05世界记录
查看>>
浅析信息化时代 医院混合云建设模式
查看>>
Gigamon针对AWS引入全面可视化平台
查看>>
DTCC2015议程曝光 最新嘉宾议题揭秘
查看>>
BAT、IBM、亚马逊、微软等一线互联网的区块链版图布局
查看>>
智能合约:开启一个新经济时代
查看>>
[翻译] JavaScript函数的6个基本术语
查看>>
vue静态资源打包中的坑与解决方案
查看>>
Lc 895. Maximum Frequency Stack 最大频率栈 JS
查看>>
j2ee分布式架构 dubbo + springmvc + mybatis + ehcache + redis 技术介绍
查看>>
Write Your Own Gemspec
查看>>
PlaNet,使用图像输入来学习世界模型
查看>>
Oracle 字符集的查看和修改【下】
查看>>
nginx + keepalive
查看>>
我的友情链接
查看>>
PHP json_encode() 函数介绍
查看>>
MyEclipse8.6 web中jsp页面出现jquery,dojo等代码自动提示
查看>>