Nancy之Pipelines三兄弟(Before After OnError)

来源:http://www.cnblogs.com/catcher1994/archive/2016/02/12/5186915.html
-Advertisement-
Play Games

Nancy中Pipelines三兄弟(Before After OnError)的簡要概述以及多種用法。


一、簡單描述

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 : BaseModule
2     {
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 ,不熟悉的可以參考

implicit (C# Reference)

有一個重寫的Wrap方法,用於把同步的包裝成非同步的形式

 1         protected override PipelineItem<Func<NancyContext, CancellationToken, Task<Response>>> Wrap(PipelineItem<Func<NancyContext, Response>> pipelineItem)
 2         {
 3             var syncDelegate = pipelineItem.Delegate;
 4             Func<NancyContext, CancellationToken, Task<Response>> asyncDelegate = (ctx, ct) =>
 5             {
 6                 var tcs = new TaskCompletionSource<Response>();
 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<Func<NancyContext, CancellationToken, Task<Response>>>(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<TDelegate> 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<TAsyncDelegate> 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 IPipelines
2     {   
3         BeforePipeline BeforeRequest { get; set; }     
4         AfterPipeline AfterRequest { get; set; }
5         ErrorPipeline OnError { get; set; }
6     }  

十分簡單的定義!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 分類:C#、Android、VS2015; 創建日期:2016-02-07 一、簡介 功能描述:用戶單擊按鈕彈出菜單。當用戶選擇一個菜單項,會觸發MenuItemClick事件並讓彈出的菜單消失;如果用戶在菜單外單擊,則直接消失彈出的菜單。當菜單消失時,會引發DismissEvent事件(利用此事件
  • 分類:C#、Android、VS2015;創建日期:2016-02-06 第4章 UI設計基礎 第3章雖然通過百度地圖應用展示了你可能感興趣的內容,但是,如果你是一個初學者,一開始就看懂和理解代碼可能會非常費勁。為瞭解決此問題,從這一章開始,本模塊將從最基本的內容講起,帶你逐步進入用C#進行Andr
  • 今天是大年初三,先跟大家拜個年,祝大家新年快樂。今天處理了一個alwaysOn問題——輔助副本因為磁碟空間不足一直顯示【未同步——可疑】,在日誌中可以看到資料庫處於掛起狀態,與主副本失去同步。原以為只需把輔助副本的磁碟做個清理,騰出一點空間,然後重啟SQL Server服務就好了(重啟讓資料庫從掛起...
  • 一、 1、現象:我們把資料庫的字元集編碼設置為utf-8,我們通過DOS界面向表的某一列插入漢字時會遇到類似 data too long for column 'name' at row 1 的錯誤。 2、錯誤原因: 3、解決的辦法: (1)set names gbk;(只對當前視窗有效) (2)找
  • 如何獲取 GemFire 8.2 安裝介質,以及在CentOS和Mac OS X的安裝過程。
  • -- 修改欄位 alter table emp MODIFY dept_id int; -- 刪除欄位 alter table emp drop COLUMN dept_id; 之前就當是 熱身了,跟著這個老師 你會覺得 真的能學到很多東西。要好好努力了! 上面兩個語句是通用性很強的語句。是 在 o
  • --1.sp_databas:列出伺服器上的所有資料庫信息,包括資料庫名稱和資料庫大小 exec sp_databases --2.sp_helpdb:報告有關指定資料庫或所有資料庫的信息 exec sp_helpdb --3.sp_renamedb:更改資料庫的名稱 exec sp_renamed
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...