NSwag Studio C# 程式產生器客製化
0 |
評估過 AutoRest、NSwag、Swagger CodeGen 的客戶端程式碼產生功能,我選擇 Swag Studio,理由是 GUI 介面友善,不依賴第三方套件,且輸出結果為單一檔案,較符合我的要求。
實務應用上,難免需要微調產出結果以符合專案的特殊要求,而我遇到的情境得支援 .NET 3.5,更是不改不行,故如何客製客戶端程式範本為首要之急,阻礙太大時甚至該當機立斷早早轉向。
經過一番研究,做到修改範本支援 .NET 3.5 版的目標,過程有點繁瑣,特整理分享給有類似需求的同學參考。
先說我的改法:在 NSwag Studio 上加一個「For .NET 3.5」選項,選取後改輸出適用 .NET 3.5 的程式碼。
.NET 3.5 版與原有版本主要差別在 .NET 3.5 沒有 System.Threading.Tasks(4.0+) 及 HttpClient(4.5+),不支援 async、await,還有一些零星小差別。一開始本想靠替代套件(System.Threading.Tasks.Unofficial、Rackspace.HttpClient35)解決,但替代程式庫與 .NET 內建版本存在差距,程式終究得改。何況依賴外部程式庫,有違選擇 NSwag Studio 的初衷,故我採行的策略是針對差異較大的部分另寫一套 .NET 3.5 樣版,細節容後再提。
修改後的 NSwag Studio 長這樣。理論上,勾選 For .NET 3.5 後,有些選項不適用該停用或隱藏(如 Inject HttpClient via constructor... 等等),但自用工具就不鈑烤打腊了,達到目的比較重要。
下面是修改細節。首先,我從 Github Fork 專案取得 NSwag 原始碼。 開啟 src/NSwag.sln,這個完整版解決方案共有 45 個專案,從核心元件、Console 程式、ASP.NET Core Middleware、自動測試、NuGet 程式包、Chocolatey 程式包到 NSwag Studio,應有盡有。
產生 C# 的樣版在 NSwag.CodeGeneration.CSharp 專案 Templates 目錄下,裡面有一堆 .liquid 附檔名的檔案,
.liquid 是 Ruby 的 Liquid Markup 樣版,用來依據 Model 物件產生 C# 程式, Liquid 語法類以這樣:
大家若有 ASP 或 cshtml 經驗,要看懂及改寫不算難。改寫幅度太大的部分,我選擇拆檔(例如上上圖中的 Client.Class.liquid 與 Client.Class35.liquid)以簡化樣版結構,由於原本的設計已模組化,有多處靠 {% template Client.Class %}
方式載入外部樣版,故可在源頭加入 if 邏輯搞定:
{% if GenerateImplementation -%}
{% if Net35Mode -%}
{% template Client.Class35 %}
{% else -%}
{% template Client.Class %}
{% endif -%}
{% endif -%}
再來是加入 Net35Mode 參數,共有幾個地方:
- NSwag.CodeGeneration.CSharp\SwaggerToCSharpClientGeneratorSettings.cs
加入 Net35Mode 屬性 - NSwag.CodeGeneration.CSharp\Models\CSharpClientTemplateModel.cs
這是要傳入 Liquid 樣版的 Model,需新增 Net35Mode 傳出 SwaggerToCSharpClientGeneratorSettings.Net35Mode - NSwag.Commands\Commands\CodeGeneration\SwaggerToCSharpClientCommand.cs
這是 NSwag Studio WPF 用的 ViewModel,也要加入 Net35Mode 屬性對應 SwaggerToCSharpClientGeneratorSettings.Net35Mode - NSwagStudio\Views\CodeGenerators\SwaggerToCSharpClientGeneratorView.xaml
在 UI 加上 Checkbox 繫結到 SwaggerToCSharpClientCommand.Net35Mode 屬性
修改後要部署 NSwag Studio 測試稍麻煩,建議可在測試專案增加測試項目,如心有餘力將測試案例補齊就更完美了。
我先在 NSwag.CodeGeneration.CSharp.Tests\SCharpClientSettingsTests.cs 加入以下方法,測試啟用 Net35Mode 時程式碼不會出現 Task,基本上就是成功了。
[Fact]
public async Task When_net35Mode_is_set_then_no_Task_is_found()
{
//// Arrange
var swaggerGenerator = new WebApiToSwaggerGenerator(
new WebApiToSwaggerGeneratorSettings());
//為假想對象 ApiController 建立 Swagger 文件
var document = await swaggerGenerator.GenerateForControllerAsync<FooController>();
//指定不同參數
var generator = new SwaggerToCSharpClientGenerator(document,
new SwaggerToCSharpClientGeneratorSettings
{
Net35Mode = true
});
//// Act
var code = generator.GenerateFile();
//// Assert
Assert.DoesNotContain("Task", code);
}
最後說一下如何執行修改版 NSwag Studio。
NSwag Studio 產生 C# 程式碼時並不是直接呼叫元件,而是在 Temp 目錄產生一個 nswag_document_75debafd-8a81-41b5-93c6-007cb39cf461_config.json 設定檔,再呼叫指定 Runtime 目錄下的 NSwag.exe(Win) / NSwag.dll(.NET Core) 命令列工具程式產生程式碼。設計成這樣是為了讓 AspNetCoreToSwaggerCommand、WebApiToSwaggerCommand、TypesToSwaggerCommand 可以在獨立 AppDomain (.NET Framework) 或 AssemblyLoadContext (.NET Core) 執行,使其與 ASP.NET 網站或 NSwag Studio 脫鉤(二者使用的平台或 DLL 版本可能不同),詳細說明可參考官方文件:NSwag Assembly loading
故要修改邏輯有多處元件要更新,netcoreapp1.0/1.1/2.0/2.1/2.2 等資料夾位於 \NSwag.ConsoleCore\bin\Release,Win 資料夾則來自 \NSwag.Console\bin\Release\net461 (再加上 \NSwag.Console.x86\bin\Release\net461\ NSwag.x86.exe & NSwag.x86.exe.config ),NSwag Studio 主程式則位於 \NSwagStudio\bin\Release (若有修改 UI 增加選項,NSwag.Commands.dll 與 NSwagStudio.exe)。
經過這番手腳,NSwag Studio 就能產生為專案量身訂做的 C# 程式碼囉~
Tutorial of how to customize the C# code template of NSwag Studio.
Comments
Be the first to post a comment