关于.net 4.0:App.Config转换为Visual Studio中不是Web项目的项目?

App.Config Transformation for projects which are not Web Projects in Visual Studio?

对于基于Visual Studio 2010 Web的应用程序,我们有配置转换功能,通过这些功能,我们可以为不同的环境维护多个配置文件。但对于Windows Services/WinForms或控制台应用程序的app.config文件,同样的功能不可用。

这里有一个建议的解决方法:将xdt magic应用到app.config。

然而,这并不简单,需要许多步骤。对于app.config文件,是否有更简单的方法来实现相同的功能?


我尝试了几种解决方案,这里是我个人发现的最简单的方法。丹在评论中指出,原来的帖子属于奥列格精神谢谢,奥列格!

以下是说明:

1。将每个配置的XML文件添加到项目中。

通常,您会有DebugRelease配置,因此将您的文件命名为App.Debug.configApp.Release.config。在我的项目中,我为每种环境创建了一个配置,因此您可能需要对此进行试验。

2。卸载项目并打开.csproj文件进行编辑

Visual Studio允许您在编辑器中直接编辑.csproj文件,只需先卸载项目即可。然后右键单击它并选择编辑.csproj。

三。将app.*.config文件绑定到主app.config

找到包含所有App.configApp.*.config引用的项目文件部分。您会注意到它们的构建操作设置为None

1
2
3
<None Include="App.config" />
<None Include="App.Debug.config" />
<None Include="App.Release.config" />

首先,将它们的构建操作设置为Content。接下来,使所有特定于配置的文件都依赖于主App.config,因此Visual Studio会像对待设计器和代码隐藏文件一样对它们进行分组。

将上面的XML替换为下面的XML:

1
2
3
4
5
6
7
<Content Include="App.config" />
<Content Include="App.Debug.config">
  <DependentUpon>App.config</DependentUpon>
</Content>
<Content Include="App.Release.config">
  <DependentUpon>App.config</DependentUpon>
</Content>

4。激活转换魔法

在文件结尾之后

1
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

在决赛之前

1
</Project>

插入以下XML:

1
2
3
4
5
6
7
8
9
10
11
12
  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="CoreCompile" Condition="exists('app.$(Configuration).config')">
    <!-- Generate transformed app config in the intermediate directory -->
    <TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
    <!-- Force build process to use the transformed configuration file from now on. -->
    <ItemGroup>
      <AppConfigWithTargetPath Remove="app.config" />
      <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
        <TargetPath>$(TargetFileName).config</TargetPath>
      </AppConfigWithTargetPath>
    </ItemGroup>
  </Target>

现在您可以重新加载项目、构建它并享受App.config转换!

供参考

确保您的App.*.config文件具有如下正确的设置:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
     <!--magic transformations here-->
</configuration>


这现在适用于本文中介绍的Visual Studio加载项:slowcheetah-web.config转换语法,现在已为任何XML配置文件进行了通用化。

You can right-click on your web.config and click"Add Config
Transforms." When you do this, you'll get a web.debug.config and a
web.release.config. You can make a web.whatever.config if you like, as
long as the name lines up with a configuration profile. These files
are just the changes you want made, not a complete copy of your
web.config.

You might think you'd want to use XSLT to transform a web.config, but
while they feels intuitively right it's actually very verbose.

Here's two transforms, one using XSLT and the same one using the XML
Document Transform syntax/namespace. As with all things there's
multiple ways in XSLT to do this, but you get the general idea. XSLT
is a generalized tree transformation language, while this deployment
one is optimized for a specific subset of common scenarios. But, the
cool part is that each XDT transform is a .NET plugin, so you can make
your own.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
  <xsl:copy>          
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="/configuration/appSettings">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
    <xsl:element name="add">
      <xsl:attribute name="key">NewSetting</xsl:attribute>
      <xsl:attribute name="value">New Setting Value</xsl:attribute>
    </xsl:element>
  </xsl:copy>
</xsl:template>
</xsl:stylesheet>

Or the same thing via the deployment transform:

1
2
3
4
5
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
   
     
   </appSettings>
</configuration>


我发现的另一个解决方案不是使用转换,而是使用一个单独的配置文件,例如app.release.config。然后将此行添加到csproj文件中。

1
2
3
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86'">
    <AppConfig>App.Release.config</AppConfig>
  </PropertyGroup>

这不仅会生成正确的myprogram.exe.config文件,而且如果您正在使用Visual Studio中的安装和部署项目来生成msi,它会在打包时强制部署项目使用正确的配置文件。


根据我的经验,我需要使环境特定的东西是连接字符串、应用程序设置和通常的smpt设置。配置系统允许在单独的文件中指定这些内容。因此,您可以在app.config/web.config中使用:

1
2
3
4
5
6
 <connectionStrings configSource="connection.config" />
 <system.net>
    <mailSettings>
       <smtp configSource="smtp.config"/>
    </mailSettings>
 </system.net>

我通常要做的是将这些特定于配置的部分放在单独的文件中,放在名为config files的子文件夹中(取决于解决方案根目录或项目级别)。我为每个配置定义一个文件,例如smtp.config.debug和smtp.config.release。

然后您可以这样定义预构建事件:

1
copy $(ProjectDir)ConfigFiles\smtp.config.$(ConfigurationName) $(TargetDir)smtp.config

在团队开发中,您可以通过在约定中包含%computername%和/或%username%来进一步调整这一点。

当然,这意味着目标文件(x.config)不应该放在源代码管理中(因为它们是生成的)。您仍然应该将它们添加到项目文件中,并将它们的输出类型属性设置为"始终复制"或"如果更新,则复制"。

简单、可扩展,适用于所有类型的Visual Studio项目(控制台、WinForms、WPF、Web)。


受Oleg和其他人在这个问题上的启发,我采取了解决方案https://stackoverflow.com/a/5109530/2286801,进一步实现了以下功能。

  • 使用ClickOnce
  • 与VS 2010中的安装和部署项目一起使用
  • 与VS2010、2013、2015一起工作(虽然也应该工作,但没有测试2012)。
  • 与团队建设合作。(必须安装a)Visual Studio或b)Microsoft.Web.Publishing.Targets和Microsoft.Web.Publishing.Tasks.dll)

此解决方案通过在msbuild进程中首次引用app.config之前执行app.config转换来工作。它使用一个外部目标文件,以便跨多个项目进行更轻松的管理。

说明:

与其他解决方案类似的步骤。我引用了保持不变的内容,并将其包括在内,以便于完整性和比较。

0。向项目中添加一个名为appconfigtransformation.targets的新文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- Transform the app config per project configuration.-->
  <PropertyGroup>
    <!-- This ensures compatibility across multiple versions of Visual Studio when using a solution file.
         However, when using MSBuild directly you may need to override this property to 11.0 or 12.0
         accordingly as part of the MSBuild script, ie /p:VisualStudioVersion=11.0;
         See http://blogs.msdn.com/b/webdev/archive/2012/08/22/visual-studio-project-compatability-and-visualstudioversion.aspx -->
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
  </PropertyGroup>

  <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.targets" />

  <Target Name="SetTransformAppConfigDestination" BeforeTargets="PrepareForBuild"
          Condition="exists('app.$(Configuration).config')">
    <PropertyGroup>
      <!-- Force build process to use the transformed configuration file from now on. -->
      <AppConfig>$(IntermediateOutputPath)$(TargetFileName).config</AppConfig>
    </PropertyGroup>
    <Message Text="AppConfig transformation destination: = $(AppConfig)" />
  </Target>

  <!-- Transform the app.config after the prepare for build completes. -->
  <Target Name="TransformAppConfig" AfterTargets="PrepareForBuild" Condition="exists('app.$(Configuration).config')">
    <!-- Generate transformed app config in the intermediate directory -->
    <TransformXml Source="app.config" Destination="$(AppConfig)" Transform="app.$(Configuration).config" />
  </Target>

</Project>

1. Add an XML file for each configuration to the project.

Typically you will have Debug and Release configurations so name your files App.Debug.config and App.Release.config. In my project, I created a configuration for each kind of enironment so you might want to experiment with that.

2. Unload project and open .csproj file for editing

Visual Studio allows you to edit .csproj right in the editor—you just need to unload the project first. Then right-click on it and select Edit .csproj.

三。将app.*.config文件绑定到主app.config

查找包含所有app.config和app.*.config引用的项目文件部分,并按以下方式替换。你会注意到我们不使用内容代替内容。

1
2
3
4
5
6
7
8
9
10
11
12
<ItemGroup>
  <None Include="app.config"/>
  <None Include="app.Production.config">
    <DependentUpon>app.config</DependentUpon>
  </None>
  <None Include="app.QA.config">
    <DependentUpon>app.config</DependentUpon>
  </None>
  <None Include="app.Development.config">
    <DependentUpon>app.config</DependentUpon>
  </None>
</ItemGroup>

4. Activate transformations magic

In the end of file after

1
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

and before final

1
</Project>

插入以下XML:

1
<Import Project="AppConfigTransformation.targets" />

完成!


您可以对每个配置使用单独的配置文件,例如app.debug.config、app.release.config,然后在项目文件中使用配置变量:

1
2
3
<PropertyGroup>
    <AppConfig>App.$(Configuration).config</AppConfig>
</PropertyGroup>

然后,根据您正在构建的配置,这将创建正确的projectname.exe.config文件。


我编写了很好的扩展来自动化app.config转换,就像一个内置的web应用程序项目配置转换一样

这个扩展的最大优点是您不需要在所有构建机器上安装它。


所以我最终选择了一个稍微不同的方法。我按照丹的步骤完成了步骤3,但添加了另一个文件:app.base.config。此文件包含每个生成的app.config中所需的配置设置。然后,我使用beforebuild(和yuri对transformxml的添加)将带有基本配置的当前配置转换为app.config。然后,构建过程正常使用转换后的app.config。然而,一个恼人的地方是,您希望以后从源代码管理中排除不断变化的app.config,但是其他的配置文件现在依赖于它。

1
2
3
4
  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="BeforeBuild" Condition="exists('app.$(Configuration).config')">
    <TransformXml Source="App.Base.config" Transform="App.$(Configuration).config" Destination="App.config" />
  </Target>

现在似乎到处都在张贴解决方案的一点改进:

1
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  • 也就是说,除非你打算永远使用你当前的vs版本


我用这个工具http://ctt.codeplex.com/解决了这个问题。我将它与ccnet/nant脚本一起用于制作包。


从Marketplace在Visual Studio中安装"配置转换工具",然后重新启动,与之相比,您还可以看到app.config的菜单预览转换。

https://marketplace.VisualStudio.com/items?项名称=golanavraham.configurationTransform


我已经创建了另一个替代方案,来替代Vishal Joshi发布的方案,在该方案中,将构建操作更改为内容的要求被删除,并且还实现了对ClickOnce部署的基本支持。我说基本,因为我没有彻底测试它,但是它应该在典型的ClickOnce部署场景中工作。

该解决方案由单个msbuild项目组成,一旦导入到现有的Windows应用程序项目(*.csproj)中,该项目将生成过程扩展为考虑app.config转换。

您可以在Visual Studio app.config xml转换中阅读更详细的解释,并且可以从GitHub下载msbuild项目文件。


如果您使用TFS在线(云版本)并希望在项目中转换app.config,则可以在不安装任何额外工具的情况下执行以下操作。从vs=>卸载项目=>编辑项目文件=>转到文件底部并添加以下内容:

1
2
3
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild" Condition="Exists('App.$(Configuration).config')">
<TransformXml Source="App.config" Transform="App.$(Configuration).config" Destination="$(OutDir)\$(AssemblyName).dll.config" />

assemblyfile和destination适用于本地使用和TFS在线(云)服务器。


当从另一个项目引用具有配置文件的类库时,建议的解决方案将不起作用(在我的例子中,它是Azure Worker项目库)。它不会将正确转换的文件从obj文件夹复制到bin\##configuration-name##文件夹中。要使其在最小的变化下工作,您需要将AfterCompile目标更改为BeforeCompile目标:

1
<Target Name="BeforeCompile" Condition="exists('app.$(Configuration).config')">