dotnet templating 定製自己的專案模板
由於工作需要,研究了一下VS 專案模板生成的相關內容,本文做一下記錄藉助.NET Core Template Engine建立一個加單的專案模板。
建立專案程式碼和配置檔案
首先建立一個Minimal 版本的Web Api專案,基於這個專案定義自己的專案模板。Template Engine 脫離$safeprojectname$這種專案模板引數的方式,好處是模板專案本身始終是一個可以正常編譯執行的專案,可以及時發現製作模板過程中的問題。
.template.config介紹
在專案根目錄下建立.template.config資料夾,存在專案相關配置檔案。資料夾內建立三個json檔案
- template.json 必須的模板配置檔案,定義一些模板配置資訊以及模板生成的邏輯等
- ide.host.json 非必須的VS介面配置檔案,定義模板圖示以及配置展示引數等
- dotnetcli.host.json 非必須的Cli配置檔案,定義命令中引數的短名稱
官方文件中給了template.json檔案必須引數的說明:
除了這三個檔案還可以增加多語言的支援,具體用法可以參考aspnetcore的專案模板
修改.template.config下的檔案
template.json
對symbols欄位做一些說明,其他必須引數上面的圖片中有說明。這裡我定義了四個引數:Framework,UseAuthorize,SeparateRouteHandler,IsLast。Framework和IsLast只作演示,UseAuthorize,SeparateRouteHandler兩個引數是定製模板時需要用到的引數。
Framework引數的datatype為choice型別,vs中會展示一個下拉列表。replaces的指定當前我們選擇的值替換專案中的哪個值,類似sourceName。其他欄位均為字面意思。
UseAuthorize,SeparateRouteHandler兩個型別為bool型別,UseAuthorize是否引入認證鑑權,演示程式碼中的判斷。SeparateRouteHandler演示模板的檔案排除邏輯,生成專案時根據該值判斷排除多餘檔案。
IsLast引數則是簡單的演示計算引數。
sources引數用來自定義輸出源,定義modifiers通過condition指定一個條件包含或者排除哪些檔案,本文使用的是exclude。
postActions則是定義模板生成後的動作,支援的Action參考文件。
更多介紹(如生成Guid,隨機數等)參考Wiki
示例檔案內容:
{ "$schema": "http://json.schemastore.org/template", "author": "Stacking", "classifications": ["web", "api"], "identity": "stacking.web.tmpl", "name": "Stacking Web Api", "shortName": "stack.tmpl", "tags": { "language": "C#", "type": "project" }, "sourceName": "Stacking.Web", "preferNameDirectory": true, "sources": [ { "modifiers": [ { "condition": "(!SeparateRouteHandler)", "exclude": ["DemoHandler.cs"] } ] } ], "symbols": { "Framework": { "type": "parameter", "description": "The target .net framework for the project.", "datatype": "choice", "choices": [ { "choice": "net6.0", "description": "Target net6.0" }, { "choice": "net5.0", "description": "Target net5.0" } ], "replaces": "net6.0", "defaultValue": "net6.0" }, "UseAuthorize": { "type": "parameter", "datatype": "bool", "defaultValue": "false", "description": "this application add authorize." }, "SeparateRouteHandler": { "type": "parameter", "datatype": "bool", "defaultValue": "false", "description": "route handler use a separate file." }, "IsLast": { "type": "computed", "value": "(Framework == \"net6.0\")" } }, "primaryOutputs": [ { "path": "Stacking.Web.csproj" } ], "postActions": [ { "description": "Restore NuGet packages required by this project.", "manualInstructions": [ { "text": "Run 'dotnet restore'" } ], "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025", "continueOnError": true } ] }
exclude指定路徑陣列支援Dic/** 以及Dic/*.cs的方式
ide.host.json
該檔案只有兩個簡單的定義,通過icon指定模板圖示(相對路徑),symbolInfo定義引數資訊,如vs上顯示哪些引數以及引數說明和預設值等。
示例檔案內容:
{ "$schema": "http://json.schemastore.org/vs-2017.3.host", "icon": "WebAPI.png", "symbolInfo": [ { "id": "Framework", "name": { "text": ".net framework" }, "description": { "text": ".net framework for the project" }, "isVisible": true, "defaultValue": "net6.0" }, { "id": "UseAuthorize", "name": { "text": "the project use authorize" }, "isVisible": true }, { "id": "SeparateRouteHandler", "name": { "text": "separate route handler file" }, "invertBoolean": false, "isVisible": true } ] }
invertBoolean引數的值為true時會將bool型別引數的值反轉,如SeparateRouteHandler的值在指定為true時,模板的判斷邏輯程式碼中這個值會變為false。
dotnetcli.host.json
cli的json檔案中只定義了一個symbolInfo引數,定義命令列方式建立模板時引數的短名稱。
示例檔案內容:
{ "$schema": "http://json.schemastore.org/dotnetcli.host", "symbolInfo": { "Framework": { "longName": "framework" }, "UseAuthorize": { "longName": "use-authorize", "shortName": "au" }, "SeparateRouteHandler": { "longName": "separate-route-handler", "shortName": "separate" } } }
自定義模板
自定義CS檔案
cs檔案自定義使用類似預編譯指令的方式 ,使用#if,#endif等命令自定義輸出邏輯
#if (SeparateRouteHandler) using Stacking.Web; #endif #if(UseAuthorize) using Microsoft.AspNetCore.Authentication.JwtBearer; #endif
如果判斷流程複雜且模板檔案變動較大可以參考aspnetcore官網模板例項,定義兩個獨立檔案再通過rename和exclude控制模板輸出內容。
{ "condition": "(UseMinimalAPIs && (IndividualAuth || OrganizationalAuth))", "rename": { "Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs": "Program.cs" }, "exclude": [ "Program.MinimalAPIs.WindowsOrNoAuth.cs" ] }
自定義csproj檔案
csproj檔案使用註釋的方式,判斷引數控制邏輯
<!--#if(UseAuthorize)--> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" /> <!--#endif-->
自定義json檔案
json檔案同樣使用註釋的方式
//#if(EnableOpenAPI) "launchUrl": "swagger", //#else "launchUrl": "weatherforecast", //#endif
安裝、解除安裝模板
在專案根目錄下執行dotnet new -i ./命令安裝自定義的模板。
解除安裝模板命令:dotnet new -u ./ 如果不是模板目錄則需要指定模板全路徑
模板釋出到nuget不再說明,寫不動了。參考官網模板定義一個templates.nuspec檔案,執行nuget.exe pack命令即可。