Middleware的藝術


定義

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);
        }
    }
NoConvert

更廣泛的Middleware

我近來在開發開源項目《NetworkSocket》,自從看到Microsoft.Owin之后的中間件之后,覺得Middleware可以在很多領域中使用,現在這個項目里的協議解析實現者都已經完全由中間件來開發,功能越來豐富,但復雜度感覺沒有增大。看看下面代碼,你應該能感覺到Middleware的甜味。

var listener = new TcpListener();
listener.Use<HttpMiddleware>();
listener.Use<JsonWebSocketMiddleware>();
listener.Use<FastMiddleware>();            
listener.Start(1212);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM