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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...