LayIM.AspNetCore Middleware 開發日記(三)基礎框架搭建

前言  

  在上一篇中簡單講了一些基礎知識,例如Asp.Net Core Middleware 的使用,DI的簡單使用以及嵌入式資源的使用方法等。本篇就是結合基礎知識來構建一個基礎框架出來。git

  那麼框架有什麼功能呢?github

  1. 攔截LayIM請求
  2. 簡單路由功能
  3. 路由調度器
  4. 通用接口

  下面就基於以上四點搭建基礎框架。其餘緩存,日誌什麼的就先不在介紹。緩存

攔截LayIM請求

  正如上一篇介紹的那樣,實現一箇中間件就能夠作攔截請求操做,換句話說,若是是layim的請求,咱們不要放過。若是不是,那麼拜拜。可是因爲咱們又使用了系統的 EmbeddedFileProvider ,因此靜態資源交給系統去處理就好。這裏呢我使用一個很簡單的方式來判斷是不是LayIM的請求,就是經過請求的path前綴去判斷。在 LayIMMiddleware入口方法Invoke中,經過IsLayIMRequest擴展方法去判斷是不是LayIM請求。代碼以下:app

     /// <summary>
        /// 是否LayIM接口請求
        /// </summary>
        /// <param name="context"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static bool IsLayIMRequest(this HttpContext context, LayIMOptions options)
        {
            return IsConfigPath(context.Request.Path.Value) || context.Request.Path.Value.StartsWith(options.ApiPrefix, StringComparison.CurrentCultureIgnoreCase);
        }

  沒錯,就這麼簡單粗暴,用了一個StartWith方法。代碼中IsConfigPath之後在講。在這裏,前綴能夠是用戶自定義的。能夠在UselayIM中傳入定義方法:框架

  app.UseLayIM(options => {
       options.ApiPrefix = "/mylayim";
  });

  好比上文中我改爲了/mylayim開頭的,測試一下。ide

  

  能夠看到,正常處理。函數

簡單路由功能

  正如上文中的路徑 /mylayim/init?uid=1 是如何進行處理的呢?這裏咱們的路由就要出場了。以前這段代碼仍是借鑑了Hangfire中 的代碼實現的。它的路由很簡單,就是經過正則去匹配。不過我這裏實現的路由沒有那麼強大,爲了方便,不少url都定義死了。並且不支持url中帶參數解析的狀況,例如 init/{uid}.不過這個後期會考慮。路由匹配代碼以下:測試

        /// <summary>
        /// 經過path找到對應的Dispatcher
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private Tuple<ILayIMDispatcher, Match> FindDispatcherMatch(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                path = "/";
            }

            foreach (var dispatcher in dispatchers)
            {
                var pattern = $"^{dispatcher.Item1}$" ;

                var match = Regex.Match(path, pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Singleline);

                if (match.Success)
                {
                    return new Tuple<ILayIMDispatcher, Match>(dispatcher.Item2, match);
                }
            }
            return null;
        }

  沒錯就這麼一個方法實現了路由,是否是很簡單。(複雜的還沒去研究。。。。)從代碼中咱們能夠看到方法返回了一個 Tuple<ILayIMDispatcher, Match> ,這個ILayIMDispatcher是何方神聖呢?讓咱們進入下一節吧。ui

路由調度器(ILayIMDispatcher)

  這個調度器翻譯的不是很準確,不過你們理解就好。若是不理解的話,看下面的圖就知道了。this

  

  接口ILayIMDispatcher裏面就一個方法

 Task Dispatch(HttpContext context);

  那麼他們又能夠細分爲多種類型,在CQRS的概念裏,咱們對聚合的增刪改都屬於命令(Command),那麼咱們能夠定義一個CommandDispatcher,不過我這裏沒有那麼嚴格按照CQRS的方式,因此查詢我也把他歸類爲查詢命令:QueryCommandDispatcher。

  下面咱們看一下具體代碼:

 internal class QueryCommandDispatcher<TResult> : CommandDispatcher<TResult>
    {
        protected override string AllowMethod => HttpGet;

        private readonly Func<HttpContext, TResult> executeFunction;
        public QueryCommandDispatcher(Func<HttpContext, TResult> executeFunction)
        {
            this.executeFunction = executeFunction;
        }
    }

  在構造函數裏面咱們傳入了一個 Func<HttpContext, TResult>,那麼這個Func就是咱們的業務邏輯了。

  好比在路由裏,咱們添加 /layim/init 的 QueryCommandDispatcher。代碼以下:

           //layim初始化接口
            routes.AddQueryCommand<object>("/init", context =>
            {
                //這裏只是演示(邏輯未實現)
                return context.Request.Query["uid"];
            });

  其中AddQueryCommand是路由的一個擴展方法:

/// <summary>
        /// 註冊返回值爲TResult類型的命令路由
        /// </summary>
        /// <typeparam name="TResult">返回類型</typeparam>
        /// <param name="routes">當前路有集合</param>
        /// <param name="path">路徑</param>
        /// <param name="command">執行命令</param>
        public static void AddQueryCommand<TResult>(this RoutesCollection routes, string path, Func<HttpContext, TResult> command)
        {
            Error.ThrowIfNull(path, nameof(path));
            Error.ThrowIfNull(command, nameof(command));

            routes.Add(path, new QueryCommandDispatcher<TResult>(command));
        }

  那麼,這樣的話,路由第一步先找到相對應  /layim/init 的調度器,而後執行Dispatch方法便可,最後返回所須要的數據。正如第一節裏的截圖那個最終處理效果。

通用接口

   通用接口其實在以前的文章中有講過,他的做用就是業務和框架解耦。也就是說我設計好一個通用接口,若是用戶不想使用框架的默認實現,能夠自行定義實現方法,而後經過依賴注入的形式替換掉框架默認實現,這裏不在贅述。好比框架的默認實現是Dapper,那麼用戶能夠本身改成EntityFramework或者其餘實現。

 

總結

  本文簡單的介紹了框架的結構和基本實現,實現較爲簡單,功能相對來講比較單一,不過因爲是偏向LayIM業務的,因此並無想把它設計的多麼複雜,功能多麼強大,並且主要是能力不夠,哈哈哈哈。

 

       博客預告:LayIM.AspNetCore Middleware 開發日記(四)主角登場(LayIM介紹)

  項目地址:https://github.com/fanpan26/LayIM.AspNetCore (本文代碼對應blog3分支或者直接查看master)歡迎小夥伴們star 圍觀 提意見。

相關文章
相關標籤/搜索