概述 XDT是Asp.net 4.0中的一個新特性,可以讓使用者在Web項目中在不同的生成類型下,快速切換配置文件(如在debug場景下使用測試配置資料庫,在Release場景下使用正式配置資料庫)。 但在非web項目中,VS並未提供如此方便的功能。這時如果我們同樣想使用xdt transforms ...
概述
XDT是Asp.net 4.0中的一個新特性,可以讓使用者在Web項目中在不同的生成類型下,快速切換配置文件(如在debug場景下使用測試配置資料庫,在Release場景下使用正式配置資料庫)。 但在非web項目中,VS並未提供如此方便的功能。這時如果我們同樣想使用xdt transforms的功能,就需要自己配置MSbuild文件。
在本例中我們是通過修改MSBuild配置文件,來使非web項目同樣可以使用XDT功能。
MSBuild全稱(Microsoft Build Engine),是用於構建應用程式的平臺。可以把他簡單的理解成Vs生成時的項目用配置,可以利用其中的配置信息對項目文件實施特定順序的操作。
項目準備
新建一個控制台項目,併在項目中創建如下的文件:
其中app.config的內容
<connectionStrings> <add name="DefaultConnection" connectionString="Data Source=TestSQLServer;Initial Catalog=MyTestDB;Integrated Security=True" providerName="System.Data.SqlClient"/> </connectionStrings>
app.debug.config的內容
<connectionStrings> <add name="DefaultConnection" connectionString="Data Source=Debug;Initial Catalog=MydebugDB;Integrated Security=True" providerName="System.Data.debug" xdt:Transform="Replace" xdt:Locator="Match(name)"/> </connectionStrings>
app.release.config的內容
<connectionStrings> <add name="DefaultConnection" connectionString="Data Source=Debug;Initial Catalog=MydebugDB;Integrated Security=True" providerName="System.Data.debug" xdt:Transform="Replace" xdt:Locator="Match(name)"/> </connectionStrings>
在控制台程式中輸出你想看到的變化的配置文件
private static readonly string DifferentConfigString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; static void Main(string[] args) { Console.Write(DifferentConfigString); Console.Read(); }
整個的項目結構最後的呈現如下的樣子(config會在具體配置後才變成如下的樣子):
具體實現:
1. 項目中引用Msbuild
2. 在系統創建%ProgramFiles (x86)%\MSBuild\Custom文件夾,把本文末尾的TransformFiles.targets文件拷貝到文件夾中,註意要修改文件中的版本號跟你安裝的Msbuild版本號一致。(本文中為簡化例子,只介紹這一種配置方式,團隊協作的配置或者單獨項目的配置會在後續的文章中說明)
3. 右鍵點擊項目->卸載項目->右鍵點擊項目->編輯.csproj 項目文件
4. 在項目文件結尾的</Project> tag上,插入如下代碼
<Import Project="$(MSBuildExtensionsPath)\Custom\TransformFiles.targets" />
5. 在項目文件中,給那些你想轉換的文件一個metadata,把TransformOnBuild設置成true.
在本例中,修改項目文件中的<None Include="App.config" />為
<None Include="App.config"> <TransformOnBuild>true</TransformOnBuild> </None>
修改<None Include="App.Debug.config" /><None Include="App.Release.config" />為
<None Include="App.Debug.config"> <DependentUpon>app.config</DependentUpon> </None> <None Include="App.Release.config"> <DependentUpon>app.config</DependentUpon> </None>
6. 重新載入項目
7. 切換解決方案配置,運行程式發現配置文件已經會自動使用不同的app.config中的內容
示例效果
在debug環境下自動使用debug參數
在release版本里自動使用release參數
實現原理
TransformFile.targets 含有兩個目標(target):DiscoverFilesToTransform,TransformAllFiles。
其中。DiscoverFilesToTransform會瀏覽所有的項 (None, Content, and Resource)。 在DiscoverFilesToTransform我查找含有%(TransformOnBuild)==true的值。當收集到所有的值以後,識別出是否有一個“app.config”會被轉換,如果是,把它放在一個特殊的項列表中,並且把其他的放在另一個項列表中。
在TransformAllFiles 中,TransformXml 任務被用來轉換所有的文件。使用屬性AfterTargets="Build;_CopyAppConfigFile",目標得以把自己註入到生成進程中。 每當生成或者_CopyAppConfigFile目標被調用,TransformAllFiles目標會被執行
以下是TransformFiles.targets文件的所有代碼
<?xml version="1.0" encoding="utf-8"?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll"/> <ItemDefinitionGroup> <!-- Set the default value to false here --> <None> <TransformOnBuild>false</TransformOnBuild> </None> <Content> <TransformOnBuild>false</TransformOnBuild> </Content> <Resource> <TransformOnBuild>false</TransformOnBuild> </Resource> <EmbeddedResource> <TransformOnBuild>false</TransformOnBuild> </EmbeddedResource> <_FilesToTransform> <IsAppConfig>false</IsAppConfig> </_FilesToTransform> </ItemDefinitionGroup> <PropertyGroup> <TransformAllFilesDependsOn> DiscoverFilesToTransform; </TransformAllFilesDependsOn> </PropertyGroup> <Target Name="TransformAllFiles" DependsOnTargets="$(TransformAllFilesDependsOn)" AfterTargets="Build;_CopyAppConfigFile"> <!-- Now we have the item list _FilesToTransformNotAppConfig and _AppConfigToTransform item lists --> <!-- Transform the app.config file --> <ItemGroup> <_AppConfigTarget Include="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" /> </ItemGroup> <PropertyGroup> <_AppConfigDest>@(_AppConfigTarget->'%(FullPath)')</_AppConfigDest> </PropertyGroup> <MakeDir Directories="@(_FilesToTransformNotAppConfig->'$(OutDir)%(RelativeDir)')" Condition="Exists('%(RelativeDir)%(Filename).$(Configuration)%(Extension)')"/> <TransformXml Source="@(_AppConfigToTransform->'%(FullPath)')" Transform="%(RelativeDir)%(Filename).$(Configuration)%(Extension)" Destination="$(_AppConfigDest)" Condition=" Exists('%(RelativeDir)%(Filename).$(Configuration)%(Extension)') " /> <TransformXml Source="@(_FilesToTransformNotAppConfig->'%(FullPath)')" Transform="%(RelativeDir)%(Filename).$(Configuration)%(Extension)" Destination="@(_FilesToTransformNotAppConfig->'$(OutDir)%(RelativeDir)%(Filename)%(Extension)')" Condition=" Exists('%(RelativeDir)%(Filename).$(Configuration)%(Extension)') " /> </Target> <Target Name="DiscoverFilesToTransform"> <!-- This will look through items list: None & Content for those with Metadata <TransformOnBuild>True</TransformOnBuild> --> <ItemGroup> <_FilesToTransform Include="@(None);@(Content);@(Resource);@(EmbeddedResource)" Condition=" '%(TransformOnBuild)' == 'true' "/> </ItemGroup> <PropertyGroup> <_AppConfigFullPath>@(AppConfigWithTargetPath->'%(RootDir)%(Directory)%(Filename)%(Extension)')</_AppConfigFullPath> </PropertyGroup> <!-- Now look to see if any of these are the app.config file --> <ItemGroup> <_FilesToTransform Condition=" '%(FullPath)'=='$(_AppConfigFullPath)' "> <IsAppConfig>true</IsAppConfig> </_FilesToTransform> </ItemGroup> <ItemGroup> <_FilesToTransformNotAppConfig Include="@(_FilesToTransform)" Condition=" '%(IsAppConfig)'!='true'"/> <_AppConfigToTransform Include="@(_FilesToTransform)" Condition=" '%(IsAppConfig)'=='true'"/> </ItemGroup> </Target> </Project>
也可以在這裡下載
其他
瞭解XDT:http://www.cnblogs.com/JustRun1983/p/3418844.html
瞭解MSbuild:http://www.cnblogs.com/l_nh/archive/2012/08/30/2662648.html
本文來源於:http://sedodream.com/2010/11/18/XDTWebconfigTransformsInNonwebProjects.aspx