用 AfterBuild 替换 <appname>.exe.config 不适用于 <appname>.vshost.exe.config

Replacing <appname>.exe.config with an AfterBuild doesn't apply to <appname>.vshost.exe.config

我们在 vbproj 中使用 AfterBuild 目标来根据所选配置替换配置文件:

<Target Name="AfterBuild" Condition="'$(Configuration)' != 'Release'">
  <Delete Files="$(TargetDir)$(TargetFileName).config" />
  <Copy SourceFiles="$(ProjectDir)$(Configuration).config" DestinationFiles="$(TargetDir)$(TargetFileName).config" />
</Target>

举个例子,假设我们有 3 个配置:调试、测试、发布。 Debug是本地调试配置。测试是用于用户验收测试的预生产环境。 Release是我们的生产环境。

App.config 文件中,我们存储了发布环境的配置。在 Debug.config 文件中,我们存储了我们本地调试需要的配置。在 Test.config 文件中,我们存储了用户接受环境的配置。

AfterBuild 目标的目标是在 building/executing 时将发布配置 (App.config) 替换为调试配置 (Debug.config) 或测试配置 ( Test.config).

当我们发布应用程序(发布,App.config)或者如果我们构建应用程序并启动 bin\<appname>.exe(调试或测试)时,一切都按预期工作。

但是,如果我们从 Visual Studio 启动应用程序,使用 Visual Studio 托管进程,正确的配置将复制到 bin\<appname>.exe.config,但似乎 Visual Studio没有将正确的配置复制到 bin\<appname>.vshost.exe.config。我们尝试清理解决方案,执行 Rebuild before 调试,在启动前手动删除 bin\<appname>.vshost.exe.config 文件,但似乎托管进程总是从默认 App.config 文件。无论我们尝试从调试配置还是测试配置开始,都会出现同样的问题。

为了增加混乱,我们创建了多个测试项目,使用相同的 AfterBuild 目标,其中一些可以正常工作,而另一些则不能。所有项目都使用 .Net Framework 4.5.1,但我们也使用 .Net 4.5 重现了该问题。它似乎不是由项目类型引起的,因为我们能够使用控制台应用程序和 Windows 表单应用程序重现该问题。

可能导致问题的原因是什么?

或者,我们可以使用其他解决方案来管理每个环境的配置吗?

注释

根据 Steve 的建议,我们将逻辑移至 BeforeCompile 目标,指定根据所选配置替换 App.config

<Target Name="BeforeCompile">
    <Delete Files="$(ProjectDir)App.config" />
    <Copy SourceFiles="$(ProjectDir)$(Configuration).config" DestinationFiles="$(ProjectDir)App.config" />
      <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
    </Copy>
</Target>

它不会每次都替换文件,当它替换时,它不一定适用于 <appname>.vshost.exe.config 文件。我们偶然发现了另一个指导我们走上正确道路的答案:Can Visual Studio automatically adjust the name of other file as it does with app.config?

添加以下 <Copy> 命令,我们实现了所需的行为:

<!--
Copy the application's .config file, if any.
Not using SkipUnchangedFiles="true" because the application may want to change
the app.config and not have an incremental build replace it.
-->
<Copy
    SourceFiles="@(AppConfigWithTargetPath)"
    DestinationFiles="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')"
    OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
    Retries="$(CopyRetryCount)"
    RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
    UseHardlinksIfPossible="$(CreateHardLinksForAdditionalFilesIfPossible)"
    >

    <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>

</Copy>

我们现在每个配置都有一个配置文件(Debug.configTest.configRelease.config)。 Visual Studio 用每个 build/launch 上的正确文件替换 App.config 文件。生成的 <appname>.vshost.exe.config 文件包含正确的参数。

奖金

此解决方案的潜在好处是我们每个配置都有一个配置文件,因此我们可以更新 .vbproj 文件并替换,例如,

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

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

所有配置文件将分组在 Visual Studio 中的主 App.config 文件下:

对我来说,它有助于禁用 VisualStudio 托管进程。

取消勾选:

Project -> Preferences -> Debug -> Enable Visual Studio hosting process

这会阻止 Visual Studio 覆盖 *config 文件。