如何仅在调试构建时运行Visual Studio后置事件

661

如何将我的“后生成事件”限制为仅针对一种类型的生成运行?

我正在使用这些事件将DLL文件复制到本地IIS虚拟目录,但我不希望在发布模式下在构建服务器上发生这种情况。

12个回答

833

预构建和后构建事件作为批处理脚本运行。您可以在$(ConfigurationName)上进行条件语句。

例如

if $(ConfigurationName) == Debug xcopy something somewhere

7
奇怪,也许只有我这样认为,但是我尝试添加了if条件,现在我收到了这个错误 - 错误代码为255。 - Michael L
7
你也可以使用goto /标签来实现更完整的解决方案(请参见我的7月24日回答)。 - CestLaGalere
12
你可以在if语句中使用括号(见我的回答中的示例)。 - gbjbaanb
2
你应该使用"xcopy /Y",这样文件将会在目标目录中被覆盖。 - Matthias
1
刚刚测试了一下,但是我不得不阅读所有的帖子才能构建一个有效的命令:(。我在下面添加了最终的命令。 - Eric Bole-Feysot
显示剩余2条评论

573

提醒一下,您不需要使用goto语句。在shell中可以使用IF命令和圆括号:

if $(ConfigurationName) == Debug (
  copy "$(TargetDir)myapp.dll" "c:\delivery\bin" /y
  copy "$(TargetDir)myapp.dll.config" "c:\delivery\bin" /y
) ELSE (
  echo "why, Microsoft, why".
)

71
我也想补充一点,要注意开括号必须紧跟在if语句后面,如果放在下一行会产生错误代码。 - wonea
48
如果你遇到错误代码255,使用"$(ConfigurationName)"(注意引号) - jgauffin
25
请注意,如果您在$(ConfigurationName)周围使用"",您还需要在单词Debug周围添加引号 - 当涉及字符串比较时,Shell命令IF语句非常字面。 - gbjbaanb
9
注意,为了去掉255,我不得不在$(ConfigurationName)周围使用"",并且去掉条件语句周围的空格,例如如果"$(ConfigurationName)"=="Release"<--等号周围没有空格。 - fhilton
17
在我的情况下,使用Visual Studio 2017时 $(ConfigurationName) 是空的(后期生成事件命令行)。if "$(Configuration)" == "Debug" 对我有用。顺便说一句,如果您想在所有其他配置中执行某些操作,请使用 if NOT "$(Configuration)" == "Debug" - Ralf Hundewadt
显示剩余9条评论

142

按照常规方式添加您的构建后事件。然后保存您的项目,在記事本(或您喜欢的编辑器)中打开,并将条件添加到PostBuildEvent属性组中。下面是一个示例:

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <PostBuildEvent>start gpedit</PostBuildEvent>
</PropertyGroup>

6
这种方法可行,但要求你必须在项目文件源码中完成所有事件的设计工作。同时,其他条件构建事件的声明也会对IDE隐藏。 - Joseph Daigle
3
我得说这是对我来说更好的答案,首选方法没起作用。 - Michael L
11
你不需要打开记事本,可以留在Visual Studio中。你可以右键点击项目文件,选择“卸载项目”,然后再次右键点击并选择“编辑”。现在,你可以使用语法高亮编辑{{csproj}}文件。再次右键点击,但这次选择“重新加载项目”来重新加载。 - Abel
2
当我尝试这种方法时,它并没有在PostBuildEvent命令本身中扩展宏。 cd "$(ProjectDir)" 扩展为 cd "" - Darryl
12
在 VS 2017 中,你也可以通过 <Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$(ConfigurationName) == Debug"> <Exec Command="your command"/></Target> 实现这一点。宏变量和所有功能都像平常一样。 - S.C.
显示剩余2条评论

111

或者(因为事件被放置在批处理文件中然后调用),使用以下内容(在“生成事件”框中,而不是在批处理文件中):

if $(ConfigurationName) == Debug goto :debug

:release
signtool.exe ....
xcopy ...

goto :exit

:debug
' Debug items in here

:exit

这种方式可以为任何配置生成事件,并仍然使用宏进行管理,而不必将它们传递到批处理文件中。请记住,%1$(OutputPath)等等。


6
如果你有机会在反编译器中查看一些代码,编译器会将许多 switch/case 语句转换为 goto。请注意,我的翻译可能不是逐字逐句的,但保留了原意并简化了语言。 - StingyJack
10
大多数编译器确实会将代码翻译为更简单的指令,例如goto语句。然而,逆向工程无法将这些简单指令组合成您想要看到的“优美”的复杂指令。我不明白微软如何强制我们使用goto,或者这与本帖有何关联。 - TamusJRoyce
1
@StingyJack:如果你查看编译后的代码,你会发现所有的代码都被转换成了JMP指令 :) 我不在乎编译器在底层做了什么,只要我能写出易读的代码就好了。(虽然有时使用goto非常容易阅读) - gbjbaanb
4
如果你愿意,你可以移除 if 并使用 goto :$(ConfigurationName)。 (注:该句话是关于编程的,为了保持准确性和简洁性,没有进行更多的解释) - Calimero100582
1
@gbjbaanb 这不是C#。这是DOS批处理脚本。在DOS批处理脚本中,“goto”一直都是完全正常的。 - Nyerguds
显示剩余6条评论

51

从Visual Studio 2019开始,现代的.csproj格式支持在Target元素上直接添加条件:

<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Debug'">
    <Exec Command="nswag run nswag.json" />
</Target>

用户界面没有提供设置此项的方法,但如果您通过用户界面进行更改,则似乎安全地保留Configuration属性。


10
这个帖子真的应该排名更靠前。另外,他们真的应该更新用户界面,允许您标记“生成配置”,或者至少添加来自csproj属性的条件。 - DeadlyChambers

19

Visual Studio 2015:正确的语法是(保持在一行上):

if "$(ConfigurationName)"=="My Debug CFG" ( xcopy "$(TargetDir)test1.tmp" "$(TargetDir)test.xml" /y) else ( xcopy "$(TargetDir)test2.tmp" "$(TargetDir)test.xml" /y)

这里没有错误 255.


5
keep it on one line - Eric Bole-Feysot
1
你的条件技巧对我来说效果最好。然而,完全不使用条件语句会更好,而且更加简洁。复制 "$(ProjectDir)..$(ConfigurationName)\MyFileName" "$(TargetDir)"。 - shawn1874
1
你的脚本是正确的,但我的脚本允许为不同的配置复制不同的文件。 - Eric Bole-Feysot

5
你可以将配置名称传递给后构建脚本,并在其中检查它是否应该运行。
使用$(ConfigurationName)传递配置名称。
检查它是基于您如何实现后构建步骤 - 它将成为命令行参数。

4
截至VS 2022,我找到了两种解决方案。在我个人的情况下,我想要根据Configuration打包到不同的目录。 选项1
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="if $(Configuration) == Debug (dotnet pack --no-build -o ~/../../../../../nuget-repo/debug -p:PackageVersion=$(VersionInfo)) else (dotnet pack --no-build -o ~/../../../../../nuget-repo -p:PackageVersion=$(VersionInfo))" />
</Target>

选项2

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Condition="'$(Configuration)' == 'Debug'" Command="dotnet pack --no-build -o ~/../../../../../nuget-repo/debug -p:PackageVersion=$(VersionInfo)" />
    <Exec Condition="'$(Configuration)' == 'Release'" Command="dotnet pack --no-build -o ~/../../../../../nuget-repo -p:PackageVersion=$(VersionInfo)" />
</Target>

我更喜欢选项2


2
我发现可以像这样在项目文件中放置多个条件:

我发现可以像这样在项目文件中放置多个条件:

  <Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition=" '$(Configuration)' != 'Debug' AND '$(Configuration)' != 'Release' ">
      <Exec Command="powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File $(ProjectDir)postBuild.ps1 -ProjectPath $(ProjectPath) -Build $(Configuration)" />
  </Target>

有趣的是,这不仅回答了我的条件问题,而且还解决了我正在寻找的问题:将Powershell作为VS Build的一部分运行。因此,我向您发送100000000000个赞和胜利。 - Frank

-1

这在我的Visual Studio 2015中有效。

我将位于库文件夹中的一个文件夹中的所有DLL文件复制到正在构建的项目的目标目录中,该文件夹与我的解决方案文件夹处于同一级别。

使用相对路径从我的项目目录开始,并向上两步进入文件夹结构..\..\lib

我的解决方案文件夹
....我的项目
Lib

if $(ConfigurationName) == Debug (
xcopy /Y "$(ProjectDir)..\..\lib\*.dll" "$(TargetDir)"
) ELSE (echo "Not Debug mode, no file copy from lib")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接