Как создать цель msbuild для запуска после цели «Выполнить» (запуск dotnet)?

#msbuild #msbuild-task

Вопрос:

Я пытаюсь создать msbuild csproj, в котором я могу вызывать dotnet run myproject и удалять папки bin/obj после выполнения. Однако CustomAfterRun цель (ниже) не выполняется после выполнения цели.

 <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 я вызываю <CallTarget Targets="Run" /> , то после сборки вызывается моя программа, и в этом случае CustomAfterRun она работает нормально !! Недостатком этого метода является то, что вывод программы виден только в том случае, если я включаю уровень детализации, а также после CustomAfterRun запуска (удаление папок bin/obj) он также попытается запустить программу СНОВА (это означает, что цель запуска вызывается ДВАЖДЫ?!) выдает мне ошибку: System.ComponentModel.Win32Exception (2): The system cannot find the file specified. .

ИЗМЕНИТЬ: В качестве альтернативы я также попытался переопределить цель запуска, но это вообще не сработало:

 <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 использовать Run цель из msbuild, однако это НЕ так. Он вызывает dotnet msbuild (при необходимости), но будет запускать выходные данные БЕЗ использования msbuild.
    Если я запущу 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>