1

My codebase contains about 30 solutions. Most of the projects in these solutions are (C#) .NET Framework, but more recently I've been adding some .NET Standard 2.0 and .NET Core 3.1 projects. All projects in all solutions build perfectly fine in Visual Studio 2019 - just click "Build" and they build.

All projects in all solutions also build in Azure DevOps (...although configuring the build pipelines to reach that point was painful).

As a convenience, I wrote a simple tool that would use the Microsoft.Build NuGet package to cycle through all solutions in the codebase and build them. This would allow me to quickly check whether I'd made any changes in one solution that broke something in another (e.g. in a shared project) without me noticing. This is where the troubles begin.

.NET Framework projects all build fine. However, when building any .NET Core project, I get build errors. These vary slightly from project to project, but all include some error similar to the following:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\VSSDK\Microsoft.VsSDK.targets(583,5):
   error MSB4018: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Build, Version=14.0.0.0, 
   Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.
   The system cannot find the file specified.

In some cases it might be Microsoft.Build.Framework instead of Microsoft Build, or it might be version 15.0.0.0 instead of 14.0.0.0, and there are always other errors in addition that arise from not being able to find the assembly it is looking for; but this appears to be the core of the problem.

The Microsoft.Build Nuget package is version 16.7.0. The only installed MSBuild version is whichever is installed with with Visual Studio 2019 version 16.7.6, which I think is 16.7.0. None of the affected projects have any apparent dependency on older versions of MSBuild, e.g. in the project their ToolsVersion="16.0", and anyway if there was something wrong with the project it wouldn't build in Visual Studio - not to mention that some of them are brand new as of only the last few days.

So, why is something(?) deciding to look for older versions of Microsoft.Build assemblies (and failing), when I'm building with a current version of Microsoft.Build assemblies, and the projects are all correct, and they all build in Visual Studio? Or - how can I find this out for myself?

BittermanAndy
  • 37
  • 2
  • 9
  • Did you use `Developer Command Prompt for VS2019` or config a path? You should check the full path of `msbuild.exe`. It seems that it looks for vs2017. Maye you could try to register your `microsoft.build.dll` into GAC. Find the `microsoft.build.dll 15.1.0.0` and then use the method from [this link](https://stackoverflow.com/questions/63019110/could-not-load-file-or-assembly-system-buffers-version-4-0-2-0/63031245#63031245). – Mr Qian Oct 30 '20 at 10:06
  • Thanks for your comment. I'm not using Developer Command Prompt, nor am I using msbuild.exe - I am using the Microsoft.Build assemblies from the NuGet package built into an app. (I specifically do not want to have to find and choose an msbuild.exe file somewhere on the file system, because that might vary. I'm using assemblies referenced by my app). – BittermanAndy Oct 30 '20 at 18:17

1 Answers1

1

It is normal, as building a complex project (and its dependencies) can load many MSBuild extensions into the memory, which can depend on another (usually older) version of MSBuild assemblies.

That's exactly why Microsoft's MSBuild.exe.config contains assembly redirection as below (and you should do the same),

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="msbuildToolsets" type="Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </configSections>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
  </startup>
  <runtime>
    <DisableFXClosureWalk enabled="true" />
    <DeferFXClosureWalk enabled="true" />
    <generatePublisherEvidence enabled="false" />
    <AppContextSwitchOverrides value="Switch.System.Security.Cryptography.UseLegacyFipsThrow=false" />
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Framework" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Conversion.Core" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Tasks.Core" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Utilities.Core" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Engine" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Conversion.Core" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
      </dependentAssembly>
      <!-- Redirects for components dropped by Visual Studio -->
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Activities.Build" culture="neutral" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="4.0.0.0" newVersion="16.0.0.0" />
        <codeBase version="16.0.0.0" href=".\amd64\Microsoft.Activities.Build.dll" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="XamlBuildTask" culture="neutral" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="4.0.0.0-16.0.0.0" newVersion="16.0.0.0" />
        <codeBase version="16.0.0.0" href=".\amd64\XamlBuildTask.dll" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.CPPTasks.Common" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <bindingRedirect oldVersion="16.0.0.0-16.7.0.0" newVersion="16.7.0.0" />
        <codeBase version="16.7.0.0" href="..\..\Microsoft\VC\v160\Microsoft.Build.CPPTasks.Common.dll" />
      </dependentAssembly>
      <!-- Workaround for crash in C++ CodeAnalysis scenarios due to https://github.com/Microsoft/msbuild/issues/1675 -->
      <dependentAssembly>
        <assemblyIdentity name="FxCopTask" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <codeBase version="16.0.0.0" href="..\..\Microsoft\VisualStudio\v16.0\CodeAnalysis\FxCopTask.dll" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.VisualStudio.CodeAnalysis" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <codeBase version="16.0.0.0" href="..\..\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.VisualStudio.CodeAnalysis.dll" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.VisualStudio.CodeAnalysis.Sdk" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
        <codeBase version="16.0.0.0" href="..\..\Microsoft\VisualStudio\v16.0\CodeAnalysis\Microsoft.VisualStudio.CodeAnalysis.Sdk.dll" />
      </dependentAssembly>
    </assemblyBinding>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
      </dependentAssembly>
    </assemblyBinding>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
      </dependentAssembly>
    </assemblyBinding>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
      </dependentAssembly>
    </assemblyBinding>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <!-- To define one or more new toolsets, add an 'msbuildToolsets' element in this file. -->
  <msbuildToolsets default="Current">
    <toolset toolsVersion="Current">
      <property name="MSBuildToolsPath" value="$([MSBuild]::GetCurrentToolsDirectory())" />
      <property name="MSBuildToolsPath32" value="$([MSBuild]::GetToolsDirectory32())" />
      <property name="MSBuildToolsPath64" value="$([MSBuild]::GetToolsDirectory64())" />
      <property name="MSBuildSDKsPath" value="$([MSBuild]::GetMSBuildSDKsPath())" />
      <property name="FrameworkSDKRoot" value="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\NETFXSDK\4.8@InstallationFolder)" />
      <property name="MSBuildRuntimeVersion" value="4.0.30319" />
      <property name="MSBuildFrameworkToolsPath" value="$(SystemRoot)\Microsoft.NET\Framework\v$(MSBuildRuntimeVersion)\" />
      <property name="MSBuildFrameworkToolsPath32" value="$(SystemRoot)\Microsoft.NET\Framework\v$(MSBuildRuntimeVersion)\" />
      <property name="MSBuildFrameworkToolsPath64" value="$(SystemRoot)\Microsoft.NET\Framework64\v$(MSBuildRuntimeVersion)\" />
      <property name="MSBuildFrameworkToolsRoot" value="$(SystemRoot)\Microsoft.NET\Framework\" />
      <property name="SDK35ToolsPath" value="$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx35Tools-x86', 'InstallationFolder', null, RegistryView.Registry32))" />
      <property name="SDK40ToolsPath" value="$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\NETFXSDK\4.8\WinSDK-NetFx40Tools-x86', 'InstallationFolder', null, RegistryView.Registry32))" />
      <property name="WindowsSDK80Path" value="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1@InstallationFolder)" />
      <property name="VsInstallRoot" value="$([MSBuild]::GetVsInstallRoot())" />
      <property name="MSBuildToolsRoot" value="$(VsInstallRoot)\MSBuild" />
      <property name="MSBuildExtensionsPath" value="$([MSBuild]::GetMSBuildExtensionsPath())" />
      <property name="MSBuildExtensionsPath32" value="$([MSBuild]::GetMSBuildExtensionsPath())" />
      <property name="RoslynTargetsPath" value="$([MSBuild]::GetToolsDirectory32())\Roslyn" />
      <!-- VC Specific Paths -->
      <property name="VCTargetsPath" value="$([MSBuild]::ValueOrDefault('$(VCTargetsPath)','$(MSBuildExtensionsPath32)\Microsoft\VC\v160\'))" />
      <property name="VCTargetsPath14" value="$([MSBuild]::ValueOrDefault('$(VCTargetsPath14)','$([MSBuild]::GetProgramFiles32())\MSBuild\Microsoft.Cpp\v4.0\V140\'))" />
      <property name="VCTargetsPath12" value="$([MSBuild]::ValueOrDefault('$(VCTargetsPath12)','$([MSBuild]::GetProgramFiles32())\MSBuild\Microsoft.Cpp\v4.0\V120\'))" />
      <property name="VCTargetsPath11" value="$([MSBuild]::ValueOrDefault('$(VCTargetsPath11)','$([MSBuild]::GetProgramFiles32())\MSBuild\Microsoft.Cpp\v4.0\V110\'))" />
      <property name="VCTargetsPath10" value="$([MSBuild]::ValueOrDefault('$(VCTargetsPath10)','$([MSBuild]::GetProgramFiles32())\MSBuild\Microsoft.Cpp\v4.0\'))" />
      <property name="AndroidTargetsPath" value="$(MSBuildExtensionsPath32)\Microsoft\MDD\Android\V150\" />
      <property name="iOSTargetsPath" value="$(MSBuildExtensionsPath32)\Microsoft\MDD\iOS\V150\" />
      <projectImportSearchPaths>
        <searchPaths os="windows">
          <property name="MSBuildExtensionsPath" value="$(MSBuildProgramFiles32)\MSBuild" />
          <property name="MSBuildExtensionsPath32" value="$(MSBuildProgramFiles32)\MSBuild" />
          <property name="MSBuildExtensionsPath64" value="$(MSBuildProgramFiles32)\MSBuild" />
          <property name="VSToolsPath" value="$(MSBuildProgramFiles32)\MSBuild\Microsoft\VisualStudio\v$(VisualStudioVersion)" />
        </searchPaths>
      </projectImportSearchPaths>
    </toolset>
  </msbuildToolsets>
</configuration>
Lex Li
  • 60,503
  • 9
  • 116
  • 147
  • 1
    After some initial confusion on my part (it was not clear to me that you were suggesting to put the assembly redirects in my own .exe.config, as I am not using MSBuild.exe.config) I can confirm that this works, thank you. Surprising to me that this isn't mentioned in the Microsoft.Build NuGet package somewhere, but there it is. For reference I only needed to redirect Microsoft.Build, Microsoft.Build.Framework, Microsoft.Build.Tasks.Core, and Microsoft.Build.Utilities.Core (as they are all that is in the NuGet package). – BittermanAndy Nov 03 '20 at 08:39