如何创建一个 msbuild 目标以在“运行”目标(dotnet 运行)之后运行?

Posted

技术标签:

【中文标题】如何创建一个 msbuild 目标以在“运行”目标(dotnet 运行)之后运行?【英文标题】:How to create a msbuild target to run after "Run" target (dotnet run)? 【发布时间】:2021-09-30 05:43:05 【问题描述】:

我正在尝试创建一个 msbuild csproj,我可以在其中调用 dotnet run myproject 并在执行后删除 bin/obj 文件夹。 但是,CustomAfterRun 目标(如下)不会在 Run 目标之后执行。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <EnableDefaultItems>false</EnableDefaultItems>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
  </ItemGroup>

  <Target Name="CustomAfterRun" AfterTargets="Run">
    <Message Importance="high" Text="[msbuild] Cleaning bin and obj..."/>
    <RemoveDir Directories="$(TargetDir)" />
    <RemoveDir Directories="$(ProjectDir)$(BaseIntermediateOutputPath)" />
  </Target>
</Project>

如果我创建一个目标CustomAfterBuild(使用AfterTargets="Build"),它可以正常工作(当我运行dotnet build myproj 时它会在构建后执行)。

这是一个错误还是我做错了什么?

还有最疯狂的部分:如果在CustomAfterBuild 内部调用&lt;CallTarget Targets="Run" /&gt;,那么在构建之后调用我的程序,在这种情况下CustomAfterRun 运行良好!这种方法的缺点是程序输出只有在我启用详细的详细级别时才可见,并且在 CustomAfterRun 运行(删除 bin/obj 文件夹)之后,它也会尝试再次运行程序(意味着运行目标是两次调用?!)给我一个错误:System.ComponentModel.Win32Exception (2): The system cannot find the file specified.

编辑:作为替代方案,我也尝试覆盖 Run 目标,但这根本不起作用:

<Project>
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <EnableDefaultItems>false</EnableDefaultItems>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
  </ItemGroup>

  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

  <Target Name="Run" >
    <Message Importance="high" Text="[msbuild] overriden..."/>
  </Target>
</Project>

【问题讨论】:

【参考方案1】:

原来我对dotnet run 有一个错误的假设。

dotnet msbuild 基本上是调用msbuild 的外观。 dotnet build 只是dotnet msbuild -restore 的快捷方式,因此它将恢复 nuget 包并构建(默认目标)。 dotnet clean 也调用 msbuild(干净的目标)。

在类似的意义上我期待 dotnet run 使用来自 msbuild 的 Run 目标,但它没有。它调用dotnet msbuild(如果需要),但它会使用 msbuild 运行输出 WITHOUT。 如果我运行msbuild -target:Run,运行后的事件就可以正常工作!

因此,一种可能的解决方案是使用普通的 msbuild。 例如:dotnet msbuild /t:Restore;Build;Run;Clean MyProj.csproj),

但是,另一个让我烦恼的行为是,当通过 msbuild 启动程序时,我在控制台输出中看不到颜色(如果有的话)。这可能是因为 msbuild 使用控制台重定向来运行我的程序。 dotnet run 幸好没有这种行为,所以我的最终解决方案是:

dotnet run &amp; dotnet clean

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <EnableDefaultItems>false</EnableDefaultItems>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
  </ItemGroup>

  <!-- Clean is not so perfect, clear leftovers -->
  <Target Name="CleanBinObj" AfterTargets="Clean">
    <RemoveDir Directories="$(ProjectDir)$(BaseOutputPath)" />
    <RemoveDir Directories="$(ProjectDir)$(BaseIntermediateOutputPath)" />
  </Target>

  <!-- If someone uses msbuild to launch, force a clean.. -->
  <Target Name="CustomAfterRun" AfterTargets="Run">
    <CallTarget Targets="Clean" />
  </Target>
</Project>

或者对于我的特定情况,我将在同一个文件夹中保留多个单独的 cs 程序(每个都有自己的 csproj),并且我想用我的文件的单独(临时)文件夹覆盖 bin/obj 文件夹:

<Project>

  <PropertyGroup>
    <TempDir>$(MSBuildProjectName).cs.tmp\</TempDir>
    <BaseOutputPath>$(TempDir)</BaseOutputPath>
    <BaseIntermediateOutputPath>$(TempDir)</BaseIntermediateOutputPath>
  </PropertyGroup>

  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <EnableDefaultItems>false</EnableDefaultItems>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="$(MSBuildProjectName).cs" />
  </ItemGroup>

  <!-- Clean is not so perfect, clear leftovers -->
  <Target Name="CleanBinObj" AfterTargets="Clean">
    <Message Importance="high" Text="Cleaning $(TempDir) (bin/obj)..."/>
    <RemoveDir Directories="$(TempDir)" />
  </Target>

  <!-- If someone uses msbuild to launch, force a clean.. -->
  <Target Name="CustomAfterRun" AfterTargets="Run">
    <CallTarget Targets="Clean" />
  </Target>
  
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

</Project>

【讨论】:

以上是关于如何创建一个 msbuild 目标以在“运行”目标(dotnet 运行)之后运行?的主要内容,如果未能解决你的问题,请参考以下文章

在 MSBuild 中为数据库项目使用 PublishProfile

运行Python脚本以在编译目标之后将文件复制到文件夹中

使用 MSBuild 将输出项传递给单独的目标

如何创建命令以在 Windows Batch 中运行其他应用程序? [关闭]

配置 Jenkins 以在 Linux 平台上运行 MSBuild

msbuild 中动态生成的 C# 文件的问题