用 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 表单应用程序重现该问题。
可能导致问题的原因是什么?
或者,我们可以使用其他解决方案来管理每个环境的配置吗?
注释
- 我们使用默认的 App.config 文件作为我们的发布环境
因为 ClickOnce 似乎不支持 AfterBuild 目标。
- 我们使用 Visual Studio Express 2013 for Windows Desktop,所以我们不能使用像 SlowCheetah 这样的任何插件。
根据 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.config
、Test.config
、Release.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 文件。
我们在 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 表单应用程序重现该问题。
可能导致问题的原因是什么?
或者,我们可以使用其他解决方案来管理每个环境的配置吗?
注释
- 我们使用默认的 App.config 文件作为我们的发布环境 因为 ClickOnce 似乎不支持 AfterBuild 目标。
- 我们使用 Visual Studio Express 2013 for Windows Desktop,所以我们不能使用像 SlowCheetah 这样的任何插件。
根据 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.config
、Test.config
、Release.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 文件。