Search code examples
msbuildcsprojdotnet-cli

Can a csproj detect if using `dotnet` or `msbuild`/`devenv` for conditions?


We have a solution that contains some WiX 3 projects that break commands like dotnet restore and dotnet test when the old style csproj tries to import Wix.CA.targets (https://github.com/wixtoolset/issues/issues/5627). dotnet restore seems to be essential since newer versions of Paket use it, and we want some .NET 8 projects within the same sln/repository root.

I don't think Wix.CA.targets does anything important for package restore and it is not a unit test, we are still using VS or MSBuild to do the actual build.

Is there some condition we can use in a .csproj file to detect when it is being loaded by a dotnet ... and exclude the import?

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <WixCATargetsPath Condition=" '$(WixCATargetsPath)' == '' ">C:\Program Files (x86)\MSBuild\Microsoft\WiX\v3.x\Wix.CA.targets</WixCATargetsPath>
    ...
  </PropertyGroup>
  ...
  <Import Project="$(WixCATargetsPath)" Condition="NotDotnetCommand" />
</Project>

> dotnet restore demo.sln
C:\Program Files (x86)\MSBuild\Microsoft\WiX\v3.x\Wix.CA.targets(42,5): error MSB4062: The "ReadRegistry" task
could not be loaded from the assembly C:\Program Files (x86)\WiX Toolset v3.11\bin\WixTasks.dll. Could not load
 file or assembly 'Microsoft.Build.Utilities, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
'. The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct, that the ass
embly and all its dependencies are available, and that the task contains a public class that implements Microso
ft.Build.Framework.ITask. [C:\Demo\Wix\Wix.csproj]

Solution

  • There is not a built-in property that will tell you that your project is being run via the dotnet tool.

    However, you can get the full command line with $([System.Environment]::CommandLine).

    <Project>
      <Target Name="CmdLine">
        <Message Text="$([System.Environment]::CommandLine)"/>
      </Target>
    </Project>
    

    If this project is named example.proj, you can test running it with the following commands:

    msbuild Example.proj
    
    dotnet build Example.proj /v:n
    
    dotnet msbuild Example.proj /v:n
    

    In my testing on Windows, the msbuild command showed msbuild as the executable but the dotnet commands showed "C:\Program Files\dotnet\sdk\8.0.101\dotnet.dll" as the executable.

    e.g.

    "C:\Program Files\dotnet\sdk\8.0.101\dotnet.dll" build Example.proj /v:n
    

    Still, you could initialize an isDotnetCommand property based on if the executable in the command line contains dotnet.