NG筆記3-使用TypeScript一文曾提及「另建程式碼產生器專案,將ViewModel規格轉成JavaScript(或TypeScript)、C#類別」的做法,方便Client及Server端共享一致的強型別ViewModel,規格如有更動,重跑程式產生器就能同步更新。
日前網友Ark詢問,有無上述做法的實際範例可供參考。先前其他專案也曾有類似程式產生器需求,手邊有運行多時的實例,但綁死過多專屬邏輯,複雜度過高難以抽離重用,算一算手邊的確缺少一組能獨立運行的淺顯範例,索性另起一套簡單的概念驗證(Proof Of Concept)範例,方便有興趣研究的同事網友參考。
範例程式碼我已放上Github,有需要的朋友請自取。以下則為簡單說明:
- 解決方案有三個專案:
- CodeGen:程式產生器,其中的Models.xml為View Model定義,只有Player、Game兩組資料物件定義。
- ViewModels:為共用程式庫(Class Library),CodeGen產生ViewModels.cs及額外ViewModel邏輯放在這裡。
- Web:ASP.NET MVC應範例,內含CodeGen產生的ViewModel.ts(TypeScript)以及呼叫MVC方法由Server端取回ViewModel的範例
- Models.xml是模型定義,實務上我更愛用Excel,編輯修改方便,甚至可交給非IT人員維護。POC力求精簡,用XML意思到了就好。
- 在CodeGen專案,Program.cs負責解析XML轉成結構化的屬性名稱、屬性型別資料。
這部分沒什麼既定規則標準,全憑開發者自行定義欄位名稱、型別、註解該怎麼標示,只要確保XML文件與轉換邏輯匹配即可。支援的型別愈多,解析程式就愈複雜,例如要涵蓋陣列、泛型、自訂型別,需定義標示方式並加入對應的解析邏輯。
我的範例只處理最基本的int、float、double、decimal、DateTime、bool、string,再加上Nullable。想要更彈性支援更多型別,請大家自由發揮。 CodeGen專案的ModelInfo及PropInfo型別用來將XML定義內容轉為.NET端的資料結構,方便後續應用。 - 將ModelInfo及PropInfo轉成C#及TypeScript型別的重任由執行期間T4範本一肩扛起,以下分別為產生C#型別及TypeScript型別的T4範本檔:
- 兩個T4範本的模型定義都來自this.Models(List<MethodInfo>),Models由Program.cs解析XML而得,要怎麼傳給T4範本呢?我習慣的做法是宣告與T4範本同名的Partial Class,新増接受List<ModelInfo>參數的建構式以及Models供T4範本使用,如此在T4中就可大大方方用this.Models取得Program.cs傳入的模型定義:
- Program.cs依以下方式將XML解析轉成List<ModelInfo>交給T4範本轉成BaseModels.cs及BaseModels.ts,產生的檔案分別寫入ViewModels專案及Web專案下的對應位置:
staticvoid Main(string[] args)
{
var models = ReadModels();
var t4csvm = new T4.CsViewModels(models);
File.WriteAllText(@"..\..\..\ViewModels\BaseModels.cs",
t4csvm.TransformText(), Encoding.UTF8);
var t4tsvm = new T4.TsViewModels(models);
File.WriteAllText(@"..\..\..\Web\Scripts\BaseModels.ts",
t4tsvm.TransformText(), Encoding.UTF8);
}
- 產生的BaseModels.cs長這樣:
BaseModels.ts長這樣: - 由於轉換所得的ViewModel型別只有屬性,如需入額外邏輯,在C#端可借用Partial Class的特性,為已有的Player型別增加建構式、屬性、方法。
注意:請避免直接修改BaseModels.cs,因為修改內容每次重跑CodeGen就會被覆寫。如果想調整BaseModels.cs,請直接修改T4範本,或使用Partial Class技巧實現。
至於TypeScript型別,雖然沒有Partial Class的概念,但可以用繼承的做法加上自訂邏輯,要客製化不是問題。 - 如此,在C#端我們就有強型別的Player可用:
在TypeScript端也有強型別的Player可用,Intellisense還能提供註解說明
未來若View Model要修改,調完XML重跑CodeGen,BaseModels.cs與BaseModels.ts就自動更新,程式端馬上有修正後的新版View Model可用,很酷吧?
希望程式範例跟說明內容夠清楚,如有不清楚之處歡迎回饋給我,我再盡力補充。