參考官方文檔:
https://docs.microsoft.com/zh-cn/dotnet/core/tools/custom-templates
https://devblogs.microsoft.com/dotnet/how-to-create-your-own-templates-for-dotnet-new/
為什么要自定義模板?
通常情況下,項目都是由多個子項目組成,相互之間有一定的依賴關系,每個子項目又有各自依賴的包,也有必需的配置項、公共代碼等。當每次創建一個相同結構的項目時,需要手動創建這些子項,手動加入依賴,復制配置項和公共代碼等,這是一個沒有技術含量、繁瑣且容易出錯的操作。雖然可以通過建立模板代碼庫達到以上效果,但是拉取代碼庫后需要修改項目名稱,剔除不需要的依賴包等,也很繁瑣。dotnet new命令提供了自定義模板能力,可以根據自己的需要,動態創建項目。
template.json介紹
該文件是創建模板必須的,它包含了創建模板所需的配置信息,下面是必須的配置項。
關於它的完整定義可參考英文文檔:https://github.com/dotnet/templating/wiki/Reference-for-template.json
目錄結構及建議
|--templates
|--mytemplate
| |--src
| |--.template.config
| | |--template.json
| |--模板源代碼
|--mytemplate01
|--src
|--.template.config
| |--template.json
|--模板源代碼
說明:
templates:可以把多個模板都放在該文件夾下,便於管理。
mytemplate:該文件夾為所需要創建的模板。如果需要多個模板,只需在其同級建立其他模板文件夾,例如mytemplate01。
src:模板源代碼存放文件夾。
.template.config/template.json:模板配置信息。
模板源代碼:存放自定義的模板源代碼。
創建簡單模板並使用
現在來創建一個簡單的模板,並進行模板的安裝和根據模板創建項目。這個模板為三層結構的WebApi項目,平台版本為.Net5,添加Sqlserver驅動包和Dapper包,接口文檔使用Swagger,並逐層注入容器。
創建模板項目
新建一個模板項目,命名SingleTplDemo,目錄結構如下:
template.json文件內容如下:
{
"$schema": "http://json.schemastore.org/template",
"author": "Bai Li",
"classifications": [ "Web/WebAPI" ],
"name": "SingleTplDemoAPI",
"identity": "SingleTplDemoAPI",
"shortName": "SingleTpl",
"tags": {
"language": "C#" ,
"type":"project"
},
"sourceName": "SingleTplDemo",
"preferNameDirectory": true
}
項目代碼結構如下:
安裝模板
使用dotnet new -i命令安裝本地模板(后面會介紹安裝遠程模板),格式如下:
dotnet new -i 模板源碼路徑
模板源碼路徑為.template.config文件夾所在的路徑。
模板安裝完成后,執行dotnet new命令,可以在已安裝模板列表中看到
使用模板創建項目
使用dotnet new命令根據指定模板創建項目,格式如下:
dotnet new 模板名稱 -n 項目名稱 -o 目標路徑
提示成功,則項目創建成功。
文件夾結構如下:
代碼結構如下:
可以看到通過這個模板創建的項目,結構和代碼文件一致。
創建動態模板
現在也創建一個三層結構的WebAPI,平台版本為.Net5,ORM使用Dapper,接口文檔使用Swagger,並逐層注入容器。跟簡單模板不同的是,數據驅動包含SqlServer和MySQL。接下來的計划是,在通過模板創建項目時,僅使用引入一種數據驅動。
創建模板項目
新建項目模板,結構目錄結構如下:
template.json文件內容如下:
{
"$schema": "http://json.schemastore.org/template",
"author": "Bai Li",
"classifications": [ "Web/WebAPI" ],
"name": "DynamicTplDemo",
"identity": "DynamicTplDemo",
"shortName": "DynamicTpl",
"tags": {
"language": "C#" ,
"type":"project"
},
"sourceName": "DynamicTplDemo",
"preferNameDirectory": true,
"symbols": {
"SqlType": {
"type": "parameter",
"description": "Sql類型",
"dataType": "choice",
"defaultValue": "MSSQL",
"isRequired": true,
"choices": [
{
"choice": "MSSQL",
"description": "MS SQL"
},
{
"choice": "MySQL",
"description": "My SQL"
}
]
},
"MSSQL": {
"type": "computed",
"value": "(SqlType == \"MSSQL\")"
},
"MySQL": {
"type": "computed",
"value": "(SqlType == \"MySQL\")"
}
}
}
該文件引入了新的配置:symbols
參考文檔:https://github.com/dotnet/templating/wiki/Reference-for-template.json#symbols
symbols配置項內的有五種類型的子項,這里僅介紹用到的兩種類型,其余的請參考官方文檔:
SqlType:作為模板的參數,在創建項目時,需要指定可選值choice。
MSSQL、MySQL:通過value中表達式計算的結果,提供給模板作為判定數據庫類型的。
項目代碼結構如下:
DbContext.cs文件中,通過預編譯指令#if等,實現MSSQL和MySQL驅動,以及對應IDbConnection實現的切換。完整內容如下:
using System.Data;
#if MSSQL
using Microsoft.Data.SqlClient;
#elif MySQL
using MySql.Data.MySqlClient;
#endif
namespace DynamicTplDemo.Infrastructure
{
/// <summary>
/// 數據庫上下文
/// </summary>
public class DbContext
{
/// <summary>
/// 連接字符串
/// </summary>
private string _connStr;
public DbContext(string connStr)
{
_connStr = connStr;
}
/// <summary>
/// 打開連接
/// </summary>
/// <returns></returns>
public IDbConnection OpenConnection()
{
IDbConnection conn = null;
#if MSSQL
conn = new SqlConnection();
#elif MySQL
conn = new MySqlConnection();
#endif
conn.ConnectionString = _connStr;
conn.Open();
return conn;
}
}
}
DynamicTplDemo.Infrastructure.csproj文件中,通過節點PackageReference的Condition屬性的表達式切換。完整內容如下:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.0-preview1.21075.2" Condition="'$(MSSQL)'=='true'" />
<PackageReference Include="MySql.Data" Version="8.0.23" Condition="'$(MySql)'=='true'" />
</ItemGroup>
</Project>
安裝模板
安裝命令:
dotnet new -i E:\SourceCode\MyPractices\MyTestTemplates\templates\DynamicTplDemo\src
查看該模板信息,執行命令:
dotnet new DynamicTpl --help
可以看到,該模板增加了選項-S|--SqlType,且該選項的可選值有MSSQL和MySQL。
使用模板創建項目
執行命令:
dotnet new DynamicTplDemoAPI -n MyDynamicApi -o E:\SourceCode\MyPractices\MyTestTemplates\codes\MyDynamicApi -S MSSQL
提示如下,則表示成功:
文件夾結構如下:
代碼結構如下,可以看到自動引入了MSSQL的驅動包:
DbContext.cs文件中,也可以看到僅包含了MSSQL的引用,以及SqlConnection類:
using System.Data;
using Microsoft.Data.SqlClient;
namespace MyDynamicApi.Infrastructure
{
/// <summary>
/// 數據庫上下文
/// </summary>
public class DbContext
{
/// <summary>
/// 連接字符串
/// </summary>
private string _connStr;
public DbContext(string connStr)
{
_connStr = connStr;
}
/// <summary>
/// 打開連接
/// </summary>
/// <returns></returns>
public IDbConnection OpenConnection()
{
IDbConnection conn = null;
conn = new SqlConnection();
conn.ConnectionString = _connStr;
conn.Open();
return conn;
}
}
}
模板打包成Nuget包,並上傳Nuget服務器
以上便是創建和使用模板的方法,但是直接將文件夾安裝為模板,不是一個好的用法。因為在實際工作中,其他機器上需要使用該模板,就要把文件夾復制過去安裝,很不方便。那這里就分享一下將模板打包稱Nuget包,並上傳到Nuget服務器,其他機器只需要執行兩行命令,就可以輕松使用上模板。
模板打包
創建文件夾
建議在templates文件夾的同級新建文件夾:packages、tools。
tools:存放工具軟件,下面內容會講到。
packages:存放生成的包,下面內容會講到
下載nuget.exe文件
下載路徑:https://www.nuget.org/downloads
選擇合適的版本,下載到上面新建的tools文件夾下。
創建.nuspec文件
參考文檔:https://docs.microsoft.com/zh-cn/nuget/create-packages/creating-a-package
在模板項目的根目錄下創建.nuspec文件,本部分內容在上面創建的動態模板上進行,故選擇命名:DynamicTplDemo.nuspec。
文件內容如下:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>DynamicTplDemo</id>
<version>1.0.0</version>
<authors>Bai Li</authors>
<description>動態模板包</description>
<copyright>Copyright ©2021 Contoso Corporation</copyright>
<packageTypes>
<packageType name="Template" />
</packageTypes>
</metadata>
<files>
<file src="src\**" target="src" exclude="**\bin\**;**\obj\**" />
</files>
</package>
官方文檔中關於節點的說明定義很清晰,可前往查閱。需要注意的是files>file節點,這里用來排除模板中各子項目下的bin和obj文件夾。
打包模板,並生成.nupkg文件
上面准備工作完成,開始進行打包。這里通過tools文件夾下的nuget.exe工具,將指定的模板項目打包稱.nupkg文件,並輸出到上面定義好的packages文件夾下。
切換到指定的項目文件夾下,執行如下命令:
E:\SourceCode\MyPractices\MyTestTemplates\tools\nuget.exe pack DynamicTplDemo.nuspec -OutputDirectory E:\SourceCode\MyPractices\MyTestTemplates\packages
當提示如下內容,則表示生成包成功。
在packages文件夾下,可以看到已生成包:
發布包
想要在不同機器上方便使用包,是需要將包發布到nuget包服務器上,通常有兩種方式:Nuget.org、私有源。
發布到Nuget.org
參考文檔:https://docs.microsoft.com/zh-cn/nuget/nuget-org/publish-a-package
發布到私有源
參考文檔:https://docs.microsoft.com/zh-cn/nuget/hosting-packages/overview
私有源有Azure、Nuget.Server、開源項目。
這里使用Baget開源項目(https://github.com/loic-sharma/BaGet),通過Docker部署,直接使用公共鏡像:
#拉取鏡像
docker pull loicsharma/baget
#運行容器
docker run --rm --name nuget-server -p 50557:80 loicsharma/baget:latest
注:此處使用公共鏡像部署僅為了簡單展示包的上傳和安裝步驟。
Baget部署后,使用nuget.exe上傳包:
參考文檔:https://docs.microsoft.com/zh-cn/nuget/reference/cli-reference/cli-ref-push
nuget.exe push E:\SourceCode\MyPractices\MyTestTemplates\packages\DynamicTplDemo.1.0.0.nupkg -src http://localhost:50557/v3/index.json
上傳成功后,可以在Baget服務器上看到上傳的包。
使用包
添加源
將上面自建的Nuget源添加到Nuget配置中,以便后面使用,添加源命令:
dotnet nuget add source http://localhost:50557/v3/index.json -n MyBaget
安裝包
dotnet new --install DynamicTplDemo::1.0.0
安裝成功后,可以看到該包:
使用包
包的使用,跟上面“創建動態模板”的“使用模板創建項目”方式一致:
dotnet new DynamicTplDemo -n MyDynamicTpl -o E:\SourceCode\MyPractices\MyTestTemplates\codes\MyDynamicTpl -S MSSQL