Getting x86 .NET 3.x tests running on the latest Azure Devops hosted agents

Background

At Black Marble we have our own private build agents, but they are built using the same Packer process as the Microsoft hosted ones. I recently rebuilt our agents to match the latest version of the hosted agents, and I ran into an issue with some .NET 3.1 based x86 MSTests. The tests were failing with the following error:

1A total of 34 test files matched the specified pattern.
2##[error]Testhost process exited with error: A fatal error occurred. The required library hostfxr.dll could not be found.
3##[error]If this is a self-contained application, that library should exist in [E:\Agent\_work\1\s\src\Ux.Common.UnitTests\bin\x86\Release\netcoreapp3.1\].
4##[error]If this is a framework-dependent application, install the runtime in the global location [C:\Program Files (x86)\dotnet] or use the DOTNET_ROOT(x86) environment variable to specify the runtime location or register the runtime location in [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation].

When I checked the folder C:\Program Files (x86)\dotnet it was not there, .NET 3.1 x86 was no longer present on the agent.

This removal of the x86 .NET SDK from the Packer build appears to have occurred around the start of the year. As when I last rebuild out agents in December 2022, they still got the x86 .NET SDK installed.

Solution

I found the solution in this GitHub issue, to use an Azure DevOps task to install the .NET 3.1 x86 SDK as part of my build pipeline

1    - task: UseDotNet@2
2      displayName: Install .NET 3.1 x86 to support vstest.console.exe
3      inputs:
4        packageType: sdk
5        version: 3.x
6      env:
7        PROCESSOR_ARCHITECTURE: x86

However, I found that it was not enough to just install the x86 SDK in this manner.

The UseDotNet@2 task installs the SDK into C:\hostedtoolcache\windows\dotnet and set the environment variable DOTNET_ROOT to point this folder, so the SDK can be found by tools that need it.

The problem is that vstest.console.exe does not seem to be aware of this environment variable, and even if DOTNET_ROOT is set it still looks in the default C:\Program Files (x86)\dotnet folder.

So I also needed to add the following PowerShell inline script to my build pipeline to also set the DOTNET_ROOT(x86) environment variable. This extra step was also detailed towards the start of the same GitHub issue when discussing manual install based workarounds, but I had initially missed it:

1    - powershell: |
2        # Set the DOTNET_ROOT(x86) so vstest.console.exe can find the SDK
3        # The UseDotNet@2 only sets the platform independant DOTNET_ROOT one that is not read by vstest.console.exe
4        Write-Host "Setting environment variable DOTNET_ROOT(x86)=$(Agent.ToolsDirectory)\dotnet"
5        Write-Host "##vso[task.setvariable variable=DOTNET_ROOT(x86)]$(Agent.ToolsDirectory)\dotnet"        
6      displayName: 'Set `DOTNET_ROOT(x86)` environment variable'
7   

So together these two steps allowed my x86 MSTest tests to run successfully again.