定義
Middleware直譯叫中間件,目前在百度上很難找到一個簡單明了的含義解釋,.Net下以前也比較難以看到它的身影,但在Microsoft.Owin里,多個地方都看到MiddleWare,我近來在嘗試理解Middleware,並在實際中模仿應用,本文章將我的個人理解和大家分享一下。
Middleware的抽象
Microsoft.Owin的Middleware
public abstract class OwinMiddleware { protected OwinMiddleware(OwinMiddleware next); protected OwinMiddleware Next { get; set; } public abstract Task Invoke(IOwinContext context); }
微軟把Middleware定義在抽象類,除了Invoke的中間件執行入口,還有一個Next的中間件屬性,兩者都是非常抽象。Invoke正是本中間件的處理邏輯,參數IOwinContext包含問題試卷和答題卡,Next表示下一個中間件,如果本中間件不想解決此問題,那么就讓Next來解決這個問題,以此類推。提問題的人不用關注是誰回答了問題,他只關注答案了夠了。
簡單的Middleware接口
如果我們把中間件定義為接口,那么一個簡單的中間件接口可以如下:
public interface IMiddleware { IMiddleware Next { set; } Answer GetAnswer(Question question); }
當然,在一些實際項目中,中間件的抽象程度不一樣,所以中間件的執行方法是根據實際需要作合理的設計,但Next一般不會有變化,它都是代表下一個中間件。
Middleware和插件的區別
插件是應用程序的功能擴展,它可以只關注自身的功能的實現,它可能不是帶問題的,但各插件的執行接口是一樣的,最簡單的插件接口可以如下:
public interface IPlug { // 加載執行插件 void Init(); }
Middleware是問題解決單元抽象,它往往是由多個單元同時協同工作,各單元雖然沒有直接關系,但Next屬性還是得到了下個中間件的實例,提供給本中間件來傳遞。Middlware隨着數量的增多,解決的問題各類也可以越多,和插件越多功能越豐富有相似。
Middleware的使用場景
我曾經寫過《.Net下一個類型轉換神器》,近期在代碼重構,發現這玩意很適合使用中間件來實現。在類型轉換中,調用者想要的是這種:
/// <summary> /// 將value轉換為目標類型 /// </summary> /// <param name="value">要轉換的值</param> /// <param name="targetType">轉換的目標類型</param> /// <returns></returns> object Convert(object value, Type targetType);
value和targetType千變萬化,一口可吃不完,本着單一職責原則,我們應該要寫很多轉換單元,每個單元只負責一種類型轉換,轉換器由N多個轉換單元組成,如果轉換單元是中間件,抽象的中間件接口應該如下:
/// <summary> /// 定義類型轉換單元的接口 /// </summary> public interface IConvertMiddleware { /// <summary> /// 設置下一個轉換單元 /// </summary> IConvertMiddleware Next { set; } /// <summary> /// 將value轉換為目標類型 /// </summary> /// <param name="上下文">context</param> /// <returns></returns> object Convert(ConvertContext context); }
實際當中,我們可能未必需要這么抽象,我的實際接口是
/// <summary> /// 定義類型轉換單元的接口 /// </summary> public interface IConvert { /// <summary> /// 設置轉換器 /// </summary> Converter Converter { set; } /// <summary> /// 設置下一個轉換單元 /// </summary> IConvert NextConvert { set; } /// <summary> /// 將value轉換為目標類型 /// </summary> /// <param name="value">要轉換的值</param> /// <param name="targetType">轉換的目標類型</param> /// <returns></returns> object Convert(object value, Type targetType); }
然后,我們來一個一個地來實現轉換單元:
某個單元的實現如下:

/// <summary> /// 表示不作轉換的轉換單元 /// </summary> public class NoConvert : IConvert { /// <summary> /// 轉換器實例 /// </summary> public Converter Converter { get; set; } /// <summary> /// 下一個轉換單元 /// </summary> public IConvert NextConvert { get; set; } /// <summary> /// 將value轉換為目標類型 /// </summary> /// <param name="value">要轉換的值</param> /// <param name="targetType">轉換的目標類型</param> /// <returns></returns> public object Convert(object value, Type targetType) { if (targetType == typeof(object)) { return value; } if (value != null && targetType == value.GetType()) { return value; } return this.NextConvert.Convert(value, targetType); } }
更廣泛的Middleware
我近來在開發開源項目《NetworkSocket》,自從看到Microsoft.Owin之后的中間件之后,覺得Middleware可以在很多領域中使用,現在這個項目里的協議解析實現者都已經完全由中間件來開發,功能越來豐富,但復雜度感覺沒有增大。看看下面代碼,你應該能感覺到Middleware的甜味。
var listener = new TcpListener(); listener.Use<HttpMiddleware>(); listener.Use<JsonWebSocketMiddleware>(); listener.Use<FastMiddleware>(); listener.Start(1212);