27

After upgrading to a csproj to use Visual Studio 2017 and Microsoft.NET.Sdk, my "BeforeBuild" and "AfterBuild" targets are no longer running. My file looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net46</TargetFramework>
  </PropertyGroup>

  <!-- my targets that don't run -->
  <Target Name="BeforeBuild">
      <Message Text="Should run before build" Importance="High" />
  </Target>

  <Target Name="AfterBuild">
      <Message Text="Should run after build" Importance="High" />
  </Target>

</Project>
Martin Ullrich
  • 94,744
  • 25
  • 252
  • 217
natemcmaster
  • 25,673
  • 6
  • 78
  • 100

3 Answers3

33

The associated MSBuild git issue recommends not using BeforeBuild/AfterBuild as task names going forward, instead name the task appropriately and wiring up against targets

<Project Sdk="Microsoft.NET.Sdk"> 
  <PropertyGroup>
    <TargetFramework>net46</TargetFramework>
  </PropertyGroup>

  <!-- Instead of BeforeBuild target -->
  <Target Name="MyCustomTask" BeforeTargets="CoreBuild" >
      <Message Text="Should run before build" Importance="High" />
  </Target>

  <!-- Replaces AfterBuild target -->
  <Target Name="AnotherCustomTarget" AfterTargets="CoreCompile">
      <Message Text="Should run after build" Importance="High" />
  </Target>    
</Project>

This gets you an idiomatic VS 2017 project file, but which targets you trigger before/after is still a matter of some debate at this time

Paul Hatcher
  • 7,342
  • 1
  • 54
  • 51
  • 1
    this also works for VS2019, should be accepted answer – dashesy Jul 26 '19 at 22:05
  • are you sure this is correct? To run something **after the build** shouldn't it be `BeforeTargets="CoreCompile"`? see https://stackoverflow.com/questions/44043918/running-a-target-before-the-corebuild – Goswin Rothenthal Sep 19 '19 at 10:13
  • 1
    @Goswin, may be but this information was lifted directly from comments in the git issue – Paul Hatcher Sep 19 '19 at 14:58
  • What is the difference between "Build" and "CoreCompile"? IOW, if I have `AfterTargets="Build"` in a nuspec file in VS2015 would that need to be changed if I want to use that nuget in VS2019 to AfterTargets="CoreCompile" – dashesy Nov 21 '19 at 22:48
12

When you specify Project Sdk="Microsoft.NET.Sdk", you are using "implicit top and bottom imports". This means there is an invisible Import to Microsoft.NET.Sdk/Sdk.targets at the bottom of your csproj file which is overriding the "BeforeBuild" and "AfterBuild" targets.

You can fix this by using explicit imports so you can control the import order.

<Project>

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

  <PropertyGroup>
    <TargetFramework>net46</TargetFramework>
  </PropertyGroup>

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

  <!-- add your custom targets after Sdk.targets is imported -->
  <Target Name="BeforeBuild">
      <Message Text="Should run before build" Importance="High" />
  </Target>

  <Target Name="AfterBuild">
      <Message Text="Should run after build" Importance="High" />
  </Target>

</Project>
natemcmaster
  • 25,673
  • 6
  • 78
  • 100
  • IS it possible to move TargetFramework property to external props file? When I tried doing that, Visual Studio gives me a "one-way upgrade" error. – Alex I Jul 17 '17 at 18:08
  • @AlexI try opening a new SO question. That's separate from what this answer is about – natemcmaster Jul 17 '17 at 18:19
  • 1
    Just did: https://stackoverflow.com/questions/45154654/vs-2017-new-project-format-and-external-props-file – Alex I Jul 17 '17 at 22:33
12

In the already mentioned GitHub issue Rainer Sigwald provides much shorter and elegant solution:

<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild"> ... </Target>
<Target Name="CustomAfterBuild" AfterTargets="AfterBuild"> ... </Target>

Looks odd, but works fine.

George Chakhidze
  • 1,269
  • 12
  • 15