在Visual Studio中不是Web项目的项目是否进行了App.Config转换?


546

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

这里有建议的解决方法:将XDT magic应用于App.Config

但是,这并不简单,需要很多步骤。有没有更简单的方法来实现相同的app.config文件?


我看过下面的文章,看起来比较简单,但我自己没有尝试过。fknut.blogspot.com/2009/11/…另外,MS Connect上有一项功能请求,可能值得投票,因此该功能将在下一个SP或版本中全面纳入。connect.microsoft.com/VisualStudio/feedback/details/564414
Kim R 2010年

Answers:


413

现在,该功能可以与本文中介绍的Visual Studio 插件一起使用SlowCheetah-Web.config转换语法现在可用于任何XML配置文件

您可以右键单击web.config,然后单击“添加配置转换”。执行此操作时,将获得一个web.debug.config和一个web.release.config。您可以根据需要创建一个web.whatever.config,只要该名称与配置配置文件对齐即可。这些文件只是您要进行的更改,而不是web.config的完整副本。

您可能会认为您想使用XSLT来转换web.config,但是尽管他们直观地感觉很对,但实际上却很冗长。

这是两种转换,一种使用XSLT,另一种使用XML Document Transform语法/命名空间。与所有事物一样,XSLT中有多种方法可以执行此操作,但是您可以大致了解。XSLT是一种通用的树转换语言,而此部署语言是针对常见方案的特定子集进行了优化的。但是,最酷的部分是每个XDT转换都是.NET插件,因此您可以自己制作。

<?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>

或通过部署转换进行相同的操作:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
   <appSettings>
      <add name="NewSetting" value="New Setting Value" xdt:Transform="Insert"/>
   </appSettings>
</configuration>

哦,太好了!拥有一个包含大量配置文件(log4net,nHibernate,web.config)的应用程序,并且记住要全部更改它们会有些麻烦。我也不希望将代码移到CruiseControl.NET中,但是看起来也很容易。
DilbertDave 2012年

10
仅供参考,SlowCheetah是一个了不起的扩展,在VS 2014之后将不再受支持。作者,Sayed Ibrahim Hashimi说sedodream.com / 2014/08/11 /…
bdeem 2014年

5
@andrewb,我在这里读过;但是那是一年前的事。重新访问该线程并阅读注释后,似乎有人在此处提供了可与VS2015一起使用的版本。
Anil Natha

2
与Visual Studio 2017和Visual STudio 2019完美配合
耶稣

1
这是这里现在
雨果·弗雷塔斯

573

我尝试了几种解决方案,这是我个人发现的最简单的解决方案。
在评论中指出,原来的职位属于奥列格Sych发表 - 感谢,奥列格!

以下是说明:

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

通常情况下,您将具有DebugRelease配置,因此请命名文件App.Debug.configApp.Release.config。在我的项目中,我为每种环境创建了一个配置,因此您可能需要尝试一下。

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

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

3.将App。*。config文件绑定到主App.config

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

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

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

将以下XML替换为以下XML:

<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.激活转换魔术(仅适用于VS2017之前的Visual Studio版本)

在文件末尾之后

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

在决赛之前

</Project>

插入以下XML:

  <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文件具有正确的设置,如下所示:

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

4
非常感谢!请注意,如果您在编辑csproj之后将新的.config文件添加到项目中,则它们将按App.config分组显示。在编辑csproj之前,我添加了一个,并且实际上以指向它的两个链接结束,一个链接分组,一个链接。
杰夫·斯文森

8
这种方法的一个问题是,当您查看项目属性中的“发布”标签,然后单击“应用程序文件”按钮...时,您会注意到app.config,app.Debug.config, app.Release.config被强制作为发布过程的一部分进行部署。当然,您也可以获得正确的MyApp.exe.config文件,但我不希望额外的负担被部署。必须有一种方法可以将项目中的app。*。config文件保留为<None>而不是<Content>。
Lee Grissom

6
一个遗漏的问题是最初从奥列格·西奇(Oleg Sych)那里得到的答案遗漏了一个关键部分。如果在您自己的应用程序(env).configs中,则不要列出'<configuration xmlns:xdt =“ schemas.microsoft.com/XML-Document-Transform ”>'和类似<appSettings xdt:Transform =“ Replace”>或在设置行上执行类似操作的属性,将无法使用。最后的信息是关键,一旦我添加了信息,所有信息便开始起作用。
djangojazz

24
您可以替换v10.0v$(VisualStudioVersion),以确保您的项目可用于所有更高版本的VS。
Thibault D.

14
我有一个错误MSBuild错误MSB3021:无法复制文件。在生成过程中找不到文件'obj \ Release \ ConsoleApp.exe'。因此,我稍微改变了解决方案以重用目标<Target Name =“ AfterBuild”>部分,而不是在解决方案中创建新的对象
asidis '18

137

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

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

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


6
MSBuild的无限奇迹。现在,我想知道还有什么可能。顺便说一句。这也可以直接用于VS的clickonce部署(与投票较高的答案相反)。
Boris B.

4
如果配置包含许多条目(对于所有构建都是相同的),则更改可能会变得繁重且容易出错。现在要处理一个环境的.config缺少更改的问题,而这当然是生产环境。
jeepwran 2015年

1
只要没有手动维护配置文件的开发人员,就可以拥有两个配置文件副本。
an IBMer 2015年

1
这是美丽的,像魅力一样!我只将<AppConfig>App.Release.config</AppConfig>行粘贴到<PropertyGroupRelease配置的现有条件中,IDE在<AppConfig>... 行下方显示了一个弯曲的行,表示该行不在架构等中,但是我还是保存了文件并重新加载了项目文件并进行了构建在Release配置中,它的工作!
湿婆

1
这样,您将失去设置设计器的功能。
的Ondrej

33

以我的经验,我需要使特定于环境的事情是诸如连接字符串,appsettings以及通常的smpt设置之类的东西。配置系统允许在单独的文件中指定这些内容。因此,您可以在app.config / web.config中使用它:

 <appSettings configSource="appsettings.config" />
 <connectionStrings configSource="connection.config" />
 <system.net>
    <mailSettings>
       <smtp configSource="smtp.config"/>
    </mailSettings>
 </system.net>

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

然后,您可以定义一个预构建事件,如下所示:

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

在团队开发中,您可以通过在约定中包括%COMPUTERNAME%和/或%USERNAME%来进行进一步调整。

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

简单,可扩展,并且适用于所有类型的Visual Studio项目(控制台,winforms,wpf,web)。


我拥有与您完全相同的配置。但是我在转换smtp文件时遇到问题。可以包含原始和转换内容吗?这些是我的:基本文件:<?xml version="1.0"?> <smtp deliveryMethod="SpecifiedPickupDirectory"> <specifiedPickupDirectory pickupDirectoryLocation="C:\mail"/> <network host="localhost"/> </smtp> 转换:<?xml version="1.0"?> <smtp xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="Replace" from="user@email.com" deliveryMethod="Network"> <network .../> </smtp>
jgarza

我不确定我是否理解。在这种配置下,我什么都不做,只是复制文件...
jeroenh

哦,我没有看到复印件。我转换配置,而不仅仅是复制它。不管怎么说,还是要谢谢你。
jgarza

我喜欢这个解决方案。一个小建议:在上面的复制示例中,复制的源和目标参数应该用引号引起来;否则,对于名称中带有空格的目录,预构建将失败
vandre

32

奥列格(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的新文件

<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.将每个配置的XML文件添加到项目中。

通常,您将具有Debug和Release配置,因此将文件命名为App.Debug.config和App.Release.config。在我的项目中,我为每种环境创建了一个配置,因此您可能需要尝试一下。

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

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

3.将App。*。config文件绑定到主App.config

找到包含所有App.config和App。*。config引用的项目文件部分,并按如下所示进行替换。您会注意到我们使用None代替Content。

<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.激活转换魔术

在文件末尾之后

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

在决赛之前

</Project>

插入以下XML:

<Import Project="AppConfigTransformation.targets" />

做完了!


1
在VS Community 2015 RC中尝试过,它忽略了我拥有的app.Debug.config文件。
Khainestar 2015年

我在一个WinForms项目中成功使用了接受的答案..但是由于某些令人困惑的原因,无法应用接受的答案。到另一个WinForms项目(全部在同一解决方案中)。@bdeem的答案是我的新宠-因为它可以与我的MSI项目正确互操作-非常感谢!
bkwdesign 2016年

这似乎在VS 2015中不起作用。我将VisualStudioVersion从10更新为12,但没有骰子。有任何想法吗?
Sinaesthetic

@Sinaesthetic您能给我们更多细节吗?VS 2015 Ultimate,社区等。VB.NET,C#,任何错误?
bdeem

VS2015企业版。没有任何错误。它什么也没做。
Sinaesthetic

27

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

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

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


谢谢,我并没有使用您的确切示例来解决我遇到的问题,但是您的示例确实让我思考,并使用“复制”任务将我引向了另一个非常相似的解决方案。
jpierson 2012年

在VS 2015 Community RC下进行了尝试并构建了它,但是随后忽略了我添加的app。*。config的内容。
Khainestar

14

我编写了不错的扩展程序来自动化app.config转换,例如内置的Web应用程序项目配置转换

此扩展程序的最大优点是您无需在所有构建计算机上都安装它


1
非常有用的扩展,尤其是在Slow Cheetah进入维护模式且将来可能不受支持的情况下。
dthrasher

是的,当transformxml msbuild任务现在支持此功能时,人们应该停止使用慢速猎豹作为解决方案。我团队中的一位软件设计师过度热情地将慢猎豹引入了我们的项目,并创建了我们所有配置的调试,转换和发布转换,其中大多数不需要转换。不用说,他离开的那一刻,我把慢猎豹拉了出来,现在我们只在web.config上使用了一个transformxml任务。啊,简单。并不是说缓慢的猎豹没有时间和地点。
HarryTuttle

5

从Marketplace在Visual Studio中安装“配置转换工具”,然后重新启动VS。您还将能够看到app.config的菜单预览转换。

https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform


1
这非常完美,几乎不需要任何努力或思考。非常感激。谢谢。(“预览转换”不起作用,但是“添加转换”在VS 2017上完全正常工作而没有问题)。似乎也经常更新。
adudley

1
非常感谢您提供的解决方案,在幕后,它确实做到了丹·阿布拉莫夫(Dan Abramov)上面所做的解释,而且不会弄脏您的手
Mohammed Dawood Ansari

这是最终的解决方案。预览似乎只是正常工作与VS 2019
凯尔冠军

1
我喜欢它,但是发现它在不对csproj进行一些编辑的情况下不支持其他非app.config文件。虽然仍然很棒,但可以预览。
Ian1971

4

所以我最终采取了稍微不同的方法。我按照Dan的步骤进行了第3步,但添加了另一个文件:App.Base.Config。此文件包含每个生成的App.Config中所需的配置设置。然后,我使用BeforeBuild(Yuri在TransformXml中添加了)将具有Base config的当前配置转换为App.config。然后,构建过程将照常使用转换后的App.config。但是,一个烦人的事是您以后想从源代码管理中排除不断变化的App.config,但是其他配置文件现在依赖于它。

  <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>

3

现在似乎已在各地发布的解决方案有了一点改进:

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

您能否解释一下您的回答或提供资料来源进行解释?
roydukkey13年

4
$(VisualStudioVersion)直接使用MSBuild时看起来好像没有设置。
杰里米·史密斯

这应该是对stackoverflow.com/a/5109530/2003763的评论(我刚刚在此处添加了与评论相同的信息)
Thibault D.

2

我创建了Vishal Joshi发布的另一种替代方法,其中删除了将生成操作更改为Content的要求,并且还实现了对ClickOnce部署的基本支持。我说基本是因为我没有对其进行彻底的测试,但是它应该可以在典型的ClickOnce部署方案中使用。

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

您可以在Visual Studio App.config XML Transformation中阅读更详细的说明,并且可以从GitHub下载 MSBuild项目文件。


1

如果您在线使用TFS(云版本)并且想要在项目中转换App.Config,则可以执行以下操作而无需安装任何其他工具。从VS =>卸载项目=>编辑项目文件=>转到文件底部并添加以下内容:

<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在线(云)服务器。


0

当从另一个项目中引用带有配置文件的类库时,建议的解决方案将不起作用(在我的情况下是Azure工作人员项目库)。它不会将正确的转换文件从obj文件夹复制到bin\##configuration-name##文件夹。为了以最小的更改使其工作,您需要将AfterCompiletarget 更改为BeforeCompile

<Target Name="BeforeCompile" Condition="exists('app.$(Configuration).config')">
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.