文章目錄
專案間如何共用 config 設定 - 使用 MSBuildExtensionPack
以往專案公司的經驗中,較常見情境是一個專案中可能會針對不同的環境建立不同的組態設定( configuration ),在發行 (publish) 時透過 configuration transformation 來將 config 設定為相對應的內容
而以產品為主的公司,需求就有些不同,相同的是還是需要為不同環境設定不同的 config,但卻多了不同專案間共用 config 設定的需求,以 連線字串
為例,在多個專案間都需要相同連線字串,而這個連線字串如果需要更新時,就是所有使用到這個連線字串的專案都要逐一調整,否則就會出現某幾個專案漏改的情況
面對上述情境,configuration transformation 就無法派上用場,這時就可以透過 msbuild 的相關功能來處理
安裝 MSBuildExtensionPack
MSBuildExtensionPack 是一個 MSBuild 的擴充套件,大大地強化了 MSBuild 的功能,今天的需求就是要借助 MSBuildExtensionPack 的幫忙,關於 MSBuildExtensionPack 的詳細內容請參考 MSBuildExtensionPack
解壓縮後依 OS 版本來執行
.msi
記得保留安裝位置
後續設定會用到
安裝完成
在專案資料夾中新增 config template
複製一份 config 並 rename 成其他名稱
範例:
Web.config.template
將 config 內容想要由共用設定決定的部份改成變數
範例:
- 在 appSettings 區段中加上一個
TestGlobalSetting
- value 則使用變數
$YowkoTest
- 在 appSettings 區段中加上一個
完整內容
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings> <add key="TestGlobalSetting" value="$YowkoTest" /> </appSettings> </configuration>
在共用資料夾中新增共用的參數設定檔
- 檔案不需要跟特定專案放在一起,方便與其他專案共用
- 關於 element 的詳細說明可以參考 MSBuild Properties
使用 xml 格式
<?xml version="1.0" encoding="utf-8"?>
以
Project
為 root element<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> </Project>
加入
PropertyGroup
element<PropertyGroup> </PropertyGroup>
將目標參數值以參數 element 包覆
<YowkoTest>ValueChanged</YowkoTest>
完整內容
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <YowkoTest>ValueChanged</YowkoTest> </PropertyGroup> </Project>
範例檔名:
properties.xml
;路徑:C:\properties.xml
在專案資料夾中新增 msbuild 定義檔
- 用來執行 config 內容取代作業
使用 xml 格式
以
Project
為 root element 並指定ToolsVersion
與DefaultTargets
ToolsVersion
只有
3.5
與4.0
兩個選擇,3.5 支援 .NET Framework 3.5;4.0 則支援 .NET Framework 4.0 以上DefaultTargets
宣告預設執行的
Target
內容,稍後會定義,名稱可自訂範例:
<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > </Project>
將
MSBuild.ExtensionPack.tasks
與參數設定檔
匯入MSBuild.ExtensionPack.tasks
存於 MSBuildExtensionPack 安裝目錄下簡易寫法
<Import Project="C:\Program Files\MSBuildExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/> <Import Project="C:\properties.xml"/>
結構寫法
加入
PropertyGroup
並加入MSBuild.ExtensionPack.tasks
與 參數設定檔 路徑<PropertyGroup> <TPath>C:\Program Files\MSBuildExtensionPack\4.0</TPath> <PropertyValues>C:\</PropertyValues> </PropertyGroup>
將
MSBuild.ExtensionPack.tasks
與參數設定檔
匯入<Import Project="$(TPath)\MSBuild.ExtensionPack.tasks"/> <Import Project="$(PropertyValues)\properties.xml"/>
兩者效果一樣,只差在如果有其他參數會共用的設定路徑時可以較簡潔
加入
ItemGroup
並設定產出檔案及 template 檔案名稱階層寫法
<ItemGroup> <ConfigFile Include="Web.config"> <Template>Web.config.template</Template> </ConfigFile> </ItemGroup>
平行寫法
<ItemGroup> <ConfigFile Include="Web.config" /> <Template Include="Web.config.template" /> </ItemGroup>
兩者效果相同,第一種寫法結構上看起來有從屬關係,但不同寫法會影響後續參數的使用,如果沒有偏好,建議使用平行寫法
加入執行動作的 Target
5-1. 複製檔案
將 template 複製一份成目標檔案
<Target Name="CopyFile"> <Copy DestinationFiles="@(ConfigFile)" SourceFiles="@(Template)" OverwriteReadOnlyFiles="true"/> </Target>
- 如果上一步使用的是階層寫法,
SourceFiles
則需改為%(Template)
,關於符號的使用請參考 Special Characters to Escape
- 如果上一步使用的是階層寫法,
5-2. 將 config 中的變數取代為
參數設定檔
中的內容- 設定名稱為
Default
與一開始Project
設定預設執行的DefaultTargets
名稱相同 - 加上
DependsOnTargets
設定,定義前一個必需優先執行的動作 加上
MSBuild.ExtensionPack.FileSystem.File
elementTaskAction
使用Replace
RegexPattern
需使用 regular expressionRegexOptionList
依需求指定Replacement
指定參數設定檔
的變數設定值注意變數名稱,因為已透過
import
指令匯入,所以需用$()
Files
指定取代的目標檔案<Target Name="Default" DependsOnTargets="CopyFile"> <MSBuild.ExtensionPack.FileSystem.File TaskAction="- " RegexPattern="\$YowkoTest" RegexOptionList="IgnoreCase|Singleline" Replacement="$(YowkoTest)" Files="@(ConfigFile)"/> </Target>
- 設定名稱為
完整內容
<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > <PropertyGroup> <TPath>C:\Program Files\MSBuildExtensionPack\4.0</TPath> <PropertyValues>C:\</PropertyValues> </PropertyGroup> <Import Project="$(TPath)\MSBuild.ExtensionPack.tasks"/> <Import Project="$(PropertyValues)\properties.xml"/> <!--<Import Project="C:\Program Files\MSBuildExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/> <Import Project="C:\properties.xml"/>--> <ItemGroup> <!--<ConfigFile Include="Web.config"> <Template>Web.config.template</Template> </ConfigFile>--> <ConfigFile Include="Web.config" /> <Template Include="Web.config.template" /> </ItemGroup> <Target Name="CopyFile"> <Copy DestinationFiles="@(ConfigFile)" SourceFiles="@(Template)" OverwriteReadOnlyFiles="true"/> </Target> <Target Name="Default" DependsOnTargets="CopyFile"> <MSBuild.ExtensionPack.FileSystem.File TaskAction="Replace" RegexPattern="\$YowkoTest" RegexOptionList="IgnoreCase|Singleline" Replacement="$(YowkoTest)" Files="@(ConfigFile)"/> </Target> </Project>
實際使用
使用 msbuild 指令執行新增的
.msbuild
定義檔"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe" msbuildextension.msbuild
執行結果
心得
文章內容不多,設定也不難,但花了不少時間看文件,尤其 msbuild 的內容很多,查了很多資料才搞清楚 msbuild 的 element 及 attribute 的定義及用法,加上 MSBuildExtensionPack 的範例資料也很少,試了好久才搞定
我覺得這個需求應該很普遍,可能有更簡單的做法,應該是我關鍵字下錯才會兜一大圈,但多學一種方法也不錯,以備不時之需
參考資訊
文章作者 Yowko Tsai
上次更新 2021-10-26
授權合約
本部落格 (Yowko's Notes) 所有的文章內容(包含圖片),任何轉載行為,必須通知並獲本部落格作者 (Yowko Tsai) 的同意始得轉載,且轉載皆須註明出處與作者。
Yowko's Notes 由 Yowko Tsai 製作,以創用CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款 釋出。