小弟之前有分享過串接【財政部查詢類電子發票API】小框架使用文
使用文連結 快速使用財政部電子發票API 使用 C# 串接文件下載 電子發票查詢API 1.4.4 程式原始碼連結
這次想跟大家分享我做出此框架的歷程..
框架目的:希望可以做出方便日後維護擴展的API。
串接API時發現他們有幾個共同之處
API請求參數名稱需降冪排列
請求參數最後會加上簽章
都有時間戳記
回應資料格式都是Json
都是使用Http (Get or Post)
我就想到可以使用 工廠模式來實作這系列產品 (工廠模式主要是切割產品的使用和生產)
產品解說 因為他們都有共同的能力**傳入一組參數回傳一串Json ** 我就先寫出一個API共同的介面簽章 IApiRunner
這個介面為基礎來撰寫後面的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 public interface IApiRunner { string ExcuteApi (object model ) ; }
我在中間多一個抽象泛型類別 ApiBase (用泛型是為了給子類決定傳入參數的Model) 原因:
中間使用泛型抽象類別讓子類決定要傳入哪組參數
可以將一些共通的方法寫在裡面
子類別只需要知道要提供哪些動作,所以在ApiBase中提供兩個方法來override
請求URL 目前預設讀取Config (GetApiURL)
參數的組合 (SetParamter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 protected abstract string SetParamter (T model ) ;protected virtual string GetApiURL (){ string apiname = this .GetType().Name; if (!ConfigurationManager.AppSettings.AllKeys.Contains(apiname)) { throw new Exception(string .Format("請確認Config的appsetting有無此參數 {0}" , apiname)); } return ConfigurationManager.AppSettings[apiname]; } public virtual string ExcuteApi (object model ){ string result = string .Empty; string postData = string .Empty; string posturl = GetApiURL(); var data = ObjectToModel(model); postData = GetInvoiceParamter(SetParamter(data)); try { ServicePointManager.ServerCertificateValidationCallback = HttpTool.ValidateServerCertificate; result = HttpTool.HttpPost(posturl, postData); } catch (Exception ex) { result = GetSysErrorMsg(); } return result; }
目前產品部分已經建構好了。
工廠解說 工廠部分這次我選擇使用【反射方式來實現工廠】
工廠類別 MoblieInvoiceApiFactroy
其實最主要是使用GetInstance方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static IApiRunner GetInstace (object model ){ if (model == null ) throw new ArgumentNullException("不能傳空的參數" ); string modelName = model.GetType().Name; return (IApiRunner)Activator.CreateInstance (GetInstanceType(model), null ); }
其中我把決定使用哪個組API的決定權交給Model並寫在標籤上(Attirbute) 在執行時他可獲取此參數Model所註冊參數的型別,來動態產生產品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static Type GetInstanceType (object model ){ var modelType = model.GetType(); var attr = modelType.GetCustomAttribute(typeof (ApiTypeAttribute)) as ApiTypeAttribute; if (attr != null ) { return GetApiType(attr); } throw new Exception("Model尚未賦予ApiTypeAttribute" ); }
EX:查詢中獎號碼API Model 可以很清楚知道這個Model隸屬於哪個API
1 2 3 4 5 [ApiType(ApiType = typeof(QryWinningListApi), MockApiType = typeof(QryWinningListMockApi)) ] public class QryWinningListModel { public string invTerm { get ; set ; } }
值得一提的是它有多一個MockApiType 為什麼會有這個? 原因:如果財政部伺服器連不到我們可以改成假資料或是模擬資料(讀取資料庫或是其他方式)。
以上就是此框架的解說
外部只需要呼叫工廠的GetInstance方法並傳入參數Model就會回傳相對應的產品API類別 這樣就降低執行和產生產品的耦合度,因為外部不是直接強耦合於Api類別而是透過工廠 日後如需增加API產品只需擴展新的類別 符合OCP(開放封閉原則) 已經達到目的:希望可以做出方便日後維護擴展的API。
Ps:這次我除了使用 工廠模式,也有用到樣板模式,代理模式 剩下兩個模式讓大家來找看看吧^^
一般來說很少只用一個模式就可以解決一個問題的,通常都是配合使用
__此文作者__:Daniel Shih(石頭) __此文地址__: https://isdaniel.github.io/InvoiceTW-Framework/ __版權聲明__:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!