多个.NET配置文件和安装项目问题

时间:2009-05-27 16:57:36

标签: c# .net visual-studio-2008 installation windows-installer

为了处理不同部署目标的设置,我将应用程序设置从app.config移动到了自己的文件,并通过configSource将该文件包含在app.config中。我还为每个目标创建了一个设置文件。这是一个例子:

Project A
   app.config (references settings.config)
   settings.config 
   settings.Release.config
   settings.Debug.config

在构建后,我将相应的设置。{configuration} .config复制到输出目录。到目前为止这工作正常,我可以在项目输出目录中看到包含当前构建配置设置的settings.config文件:Release,Debug等。

但是,我对此项目的安装项目有问题(项目A)。最初,它不包括settings.config文件。所以我将settings.config文件的构建操作设置为Content,并将项目A中的内容文件添加到安装项目中。这确保了settings.config文件包含在设置中。但是,由于安装项目似乎是从项目目录而不是输出目录中选择settings.config文件,因此安装程序中包含的settings.config文件不是它应该的样子。我希望输出目录中的那个包含在安装程序中,因为那个是当前构建配置的正确选项。我尝试了以下方法:

  • 将settings.config作为文件添加到安装项目中。但是,似乎我只能指定绝对路径。因此,当我从特定构建配置的输出目录(..bin \ debug \ settings.config)添加它时,它在其他构建配置中不起作用,因为(..bin \ debug \ settings.config)确实存在于目录指定。我研究了在安装项目中使用相对路径或动态路径,其中构建配置可以指定为路径的一部分,但我找不到任何东西。

我考虑使用预构建事件来实际修改项目目录中的settings.config文件,然后通过将其“复制到输出目录”设置为始终复制或复制(如果较新)将其复制到输出目录中。这应确保将相应的settings.config复制到输出目录,就像基于构建后的解决方案一样,并且还应确保在安装项目包含之前更新settings.config文件的内容。但是,我不喜欢这个解决方案,因为在我可以进行任何更改之前,我必须确保settings.config文件是可写的,因为它是源代码控制的。如果它是只读的,那么我需要将其翻转为可写,进行更改,然后再将其设置为只读。它增加了额外的复杂性。

我想知道是否有人有更好的想法或知道一个安装项目技巧,允许我在安装程序中包含适用于当前构建配置的settings.config文件。

由于

2 个答案:

答案 0 :(得分:1)

如果我不得不解决这个问题,我首先会提出以下问题:

如果settings.Debug.config或settings.Release.config提供相同的信息,为什么settings.config必须受源代码控制?

如果我正确地阅读了您的问题,答案是因为您需要强制settings.config文件作为构建输出的一部分出现。我猜这是因为您的安装项目使用内置的“主输出”选项。

您可以做的是将该文件作为显式文件引用添加到您的安装项目中。右键单击安装项目并选择添加/文件,然后选择要包含的文件。正如您将注意到的那样(除非它已经在VS2008中得到修复,遗憾的是我还不允许在工作中使用),对手动添加的文件存在非常恼人的限制 - 没有办法让路径构建配置知道。您可以通过将相应的settings.config文件复制到公共位置(例如bin / Configuration)并从那里拾取它来解决此问题。这确实限制了您按顺序构建Debug和Release版本,而不是并行构建,但对于许多人而言,这可能不是一个大问题。

如果您不需要使用VS安装项目,我强烈建议您查看WiX(Windows Installer XML - 有关详细信息,请参阅http://wix.sourceforge.net/)。这将很容易让您完成必要的工作,但如果您不熟悉Microsoft Installer的内部工作原理,初始学习曲线可能会有点陡峭。 Microsoft将自己的WiX用于一些非常重要的设置任务(例如Office 2007,SQL Server等)。希望WiX成为Visual Studio的一部分(适用于VS 2010),但遗憾的是,情况已不再如此。

答案 1 :(得分:1)

我决定以不同的方式实现相同的结果(能够为不同的目标环境设置不同的配置)。所以这就是我如何实现它并且它工作得很好。我在这里阅读了一些关于来自MSBuild Community Tasks的XmlMassUpdate任务的帖子,并决定使用它。这是我做的:

1)对于每个需要根据目标环境设置不同的项目,我将一个名为app.config.substitutions.xml或web.config.substitutions.xml的xml文件添加到项目中。所以,该项目看起来像

Project A   
 app.config 
 app.config.substitutions.xml

app.config.substitutions.xml文件具有XmlMassUpdate将处理并应用于app.config文件的设置替换。下面是我使用的示例替换文件:

<configuration xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
  <substitutions>
    <Development>
      <appSettings>
        <add xmu:key="key" key="SomeSetting" value="DevValue" />
      </appSettings>
    </Development>
    <Test>
      <appSettings>
        <add xmu:key="key" key="SomeSetting" value="TestValue" />
      </appSettings>
    </Test>
    <Release>
      <appSettings>
        <add xmu:key="key" key="SomeSetting" value="ReleaseValue" />
      </appSettings>
    </Release>
  </substitutions>
</configuration>

有关如何指定替换的详细信息,请查看XmlMassUpdate的文档或只是对其进行搜索。

2)现在我需要运行XmlMassUpdate作为构建自动化(TeamBuild / MSBuild)的一部分。因此,在TeamBuild构建定义文件(基本上是一个proj文件)中的BeforeCompile中,我添加了以下内容以在具有相应.substitution.xml文件的配置文件上运行XmlMassUpdate

  <PropertyGroup>
    <SubstitutionFileExtension>.substitutions.xml</SubstitutionFileExtension>
    <TargetEnvironment>Test</TargetEnvironment>
  </PropertyGroup>

  <Target Name="BeforeCompile" Condition="'$(IsDesktopBuild)'!='true'">
    <CreateItem Include="$(SolutionRoot)\**\app.config;$(SolutionRoot)\**\web.config">
      <Output ItemName="ConfigurationFiles" TaskParameter="Include"/>
    </CreateItem>
    <CreateItem Include="@(ConfigurationFiles)" Condition="Exists('%(FullPath)$(SubstitutionFileExtension)')">
      <Output ItemName="ConfigFilesWithSubstitutions" TaskParameter="Include"/>
    </CreateItem>
    <Message Text="Updating configuration files with deployment target specific settings..."/>
    <XmlMassUpdate
      ContentFile="%(ConfigFilesWithSubstitutions.FullPath)"
      SubstitutionsFile="%(ConfigFilesWithSubstitutions.FullPath)$(SubstitutionFileExtension)"
      ContentRoot="/configuration"
      SubstitutionsRoot="/configuration/substitutions/$(TargetEnvironment)"/>   
  </Target>

请注意,配置文件在构建期间是只读的,我确保在运行此任务之前将它们设置为可写。我实际上有另一个自定义MSBuild任务,它在XmlMassUpdate之前运行,它处理所有配置文件(如连接字符串)中的常见设置。该任务使配置文件可写。我也不会将修改后的配置文件检查回源代码控制。它们是(安装程序中包含的适当的部署目标配置文件)。