为什么我的自定义 MSBuild 脚本在从 Visual Studio 调用时无法复制项目引用?

Why is my custom MSBuild script not able to copy project references when invoked from Visual Studio?

我正在尝试通过提供一个安装程序来简化我们的一个 Web 项目的部署,该安装程序负责处理应用程序需要初始化的所有事情。我选择了 WiX toolset for this and created a custom build script following this and partly this tutorial。要重现我面临的问题,您可以下载第一个教程的源代码link。

我的总体目标是能够直接从 Visual Studio 创建安装程序。本教程描述了如何编写生成安装程序的构建脚本。基本上,我想通过在 Visual Studio(2012 年,如果重要的话)中单击 "Build" 来调用此脚本。

首先,我在解决方案中添加了一个 WiX 项目(将其重新定位到 setup 目录!)。我已经添加了所有设置文件和所需的 WiX 参考(UI、Util、IIS、SQL)。通过现在简单地调用构建,WiX 会抱怨未定义的 var.publishDir 变量。所以我 运行 在 VS 开发人员控制台中使用以下命令提供的构建脚本:

msbuild /t:Build;CreateInstaller;DeleteTmpFiles build_setup.build

首先,这给了我一个错误 9009(找不到命令),当我试图调用 heat 工具进行收获时。我通过将 "$(WixPath)heat" 调用替换为 "$(WiX)\bin\heat" 来修复此问题。在那之后一切都按预期工作,所以我开始连接到 .wixproj 文件的构建过程,以便从那里调用构建脚本。我通过定义以下构建目标(在项目组下方)来做到这一点:

<Target Name="Build">
  <MSBuild Projects="build_setup.build" Targets="Build;CreateInstaller" Properties="" />
</Target>
<Target Name="Rebuild">
  <MSBuild Projects="build_setup.build" Targets="Build;CreateInstaller;DeleteTmpFiles" Properties="" />
</Target>
<Target Name="Clean">
  <MSBuild Projects="build_setup.build" Targets="DeleteTmpFiles" Properties="" />
</Target>

我还检查了安装程序项目是否从所有配置的构建配置管理器内的解决方案范围构建中排除(但特别是 Release|AnyCPU,因为这是部署所需的配置)。为了清楚起见,我在 build_setup.build 脚本中修复了两个 MSBuild 调用并添加了我想要的平台:

<!-- Define default target with name 'Build' -->
<Target Name="Build">
  <!-- Compile whole solution in release mode -->
  <MSBuild Projects="..\MyWeb\MyWeb.sln" Targets="ReBuild"
      Properties="Configuration=Release;Platform=Any CPU" />
</Target>

<!-- Define creating installer in another target -->
<Target Name="CreateInstaller">
  <RemoveDir Directories="$(PublishF)" ContinueOnError="false" />
  <MSBuild Projects="..\MyWeb\MyWeb\MyWeb.csproj" Targets="ResolveReferences;_CopyWebApplication"
      Properties="OutDir=$(Publish)bin\;WebProjectOutputDir=$(Publish);Configuration=Release;Platform=AnyCPU" />
  <!-- ... -->
</Target>

现在,当我通过右键单击安装程序项目和 "Build" 调用构建时,构建已从 Visual Studio 成功触发 - 正是我想要的。

问题从添加项目引用开始:我添加了一个新的库项目(在其中定义了一个简单的 class,从网站引用了该库并创建了一个库实例 class 那里)。现在,当我尝试从 Visual Studio 构建项目时,我收到一个错误,指出无法从 发布目录复制引用的程序集,因为它不存在:

Microsoft.WebApplication.targets(175,5): error MSB3030: Could not copy file "...\WixWebDeploy\Setup\publish\bin\MyWeb.Model.dll" because it was not found.

最重要的是,如果我从开发人员控制台调用构建脚本,一切正常!此外,这只会影响项目引用(项目使用目标 ResolveReferences_CopyWebApplication 发布)。复制 NuGet 包或静态库引用没有任何问题。

我很感激任何能为我指明解决这个问题的正确方向的想法。例如,我对从控制台调用 msbuild 或 Visual Studio(如果有的话...)之间的区别感兴趣。提前致谢!

我终于想出了解决这个问题的方法。解决方案是 使用 OutputPath 参数而不是 OutDir 从 MSBuild 调用命令行脚本:

<Target Name="Build">
  <Exec Command="echo Building solution with '$(MSBuildToolsPath)\msbuild'..." />
  <!--<MSBuild Projects="build_setup.build" Targets="CreateInstaller" Properties="Configuration=Release;Platform=AnyCPU" />-->
  <Exec Command="call build_setup.cmd $(MSBuildToolsPath) CreateInstaller" />
</Target>
<Target Name="Rebuild">
  <Exec Command="echo Building solution with '$(MSBuildToolsPath)\msbuild'..." />
  <!--<MSBuild Projects="build_setup.build" Targets="Build;CreateInstaller" Properties="" />-->
  <Exec Command="call build_setup.cmd $(MSBuildToolsPath) Build CreateInstaller" />
</Target>
<Target Name="Clean">
  <Exec Command="echo Building solution with '$(MSBuildToolsPath)\msbuild'..." />
  <!--<MSBuild Projects="build_setup.build" Targets="DeleteTmpFiles" Properties="" />-->
  <Exec Command="call build_setup.cmd $(MSBuildToolsPath) DeleteTmpFiles" />
</Target>

build_setup.cmd 我再次调用 MSBuild:

if [%1] == [] (
    echo "Please supply the msbuild directory as first argument!"
    exit 10
) else (
    set MSBUildDir=%1
)

if [%2] == [] (
    echo "You have to supply at least one of the following arguments: Build, CreateInstaller, DeleteTmpFiles!"
    exit 11
) else if [%3] == [] (
    echo "%MSBUildDir%\msbuild /t:%2 setup.build"
    call %MSBUildDir%\msbuild /t:%2 setup.build
    exit 0
) else if [%4] == [] (
    echo "%MSBUildDir%\msbuild /t:%2;%3 setup.build"
    call %MSBUildDir%\msbuild /t:%2;%3 setup.build
    exit 0
) else (
    echo "%MSBUildDir%\msbuild /t:%2;%3;%4 setup.build"
    call %MSBUildDir%\msbuild /t:%2;%3;%4 setup.build
    exit 0
)

这个接缝有点多余,也许有人有更好的建议。