Ubuntu Jammy casualties: dotnet

Before I upgraded to Ubuntu 22.04 (Jammy), I had dotnet 5 and 6 installed, rather out of interest, than doing any serious programming.

As far as I can remember, I originally had installed the Snap version of dotnet, but had troubles installing any dotnet packages or templates, so I had switched to the “native” version of dotnet, probably using the dotnet-install.sh variant – I’m not sure.

Upgrading to 22.04 seems to have uninstalled dotnet 5, as it is out of support, and weird things happened to the dotnet 6 installation:

Running

dotnet new -i Avalonia.Templates

did not install the expected templates, but rather immediately returned the error message

The application ‘new’ does not exist

Further, the command dotnet --info listed two 6.0 runtimes, but did not know of any previously installed SDKs.

After uninstalling and re-installing and uninstalling the dotnet6 package, the command dotnet was still there, but did not do anything useful.

$ dotnet --list-sdks
A fatal error occurred. The folder [/usr/lib/dotnet/dotnet6-6.0.108/host/fxr] does not exist

This error message got me to dotnet/core Issue 5746 (dealing with .Net Core 3 on CentOS though), where a comment states

This can happen if dotnet-host and dotnet-hostfxr-3.1 are conflicting,

So I queried apt for the list of installed dotnet packages

$ apt list | grep dotnet

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

dotnet-apphost-pack-5.0/now 5.0.17-1 amd64 [installed,local]
dotnet-apphost-pack-6.0/jammy-updates,jammy-security,now 6.0.109-0ubuntu1~22.04.1 amd64 [installed,auto-removable]
dotnet-host/jammy-updates,jammy-security 6.0.109-0ubuntu1~22.04.1 amd64 [upgradable from: 6.0.108-0ubuntu1~22.04.1]
dotnet-hostfxr-5.0/now 5.0.17-1 amd64 [installed,local]
dotnet-hostfxr-6.0/jammy-updates,jammy-security,now 6.0.109-0ubuntu1~22.04.1 amd64 [installed,auto-removable]
dotnet-runtime-6.0/jammy-updates,jammy-security 6.0.109-0ubuntu1~22.04.1 amd64
dotnet-runtime-deps-5.0/now 5.0.17-1 amd64 [installed,local]
dotnet-sdk-6.0-source-built-artifacts/jammy-updates,jammy-security 6.0.109-0ubuntu1~22.04.1 amd64
dotnet-sdk-6.0/jammy-updates,jammy-security 6.0.109-0ubuntu1~22.04.1 amd64
dotnet-targeting-pack-5.0/now 5.0.0-1 amd64 [installed,local]
dotnet-targeting-pack-6.0/jammy-updates,jammy-security,now 6.0.109-0ubuntu1~22.04.1 amd64 [installed,auto-removable]
dotnet-templates-6.0/jammy-updates,jammy-security,now 6.0.109-0ubuntu1~22.04.1 amd64 [installed,auto-removable]
dotnet6/jammy-updates,jammy-security 6.0.109-0ubuntu1~22.04.1 amd64
libgtk-dotnet3.0-cil-dev/jammy 2.99.3-4build1 amd64
libgtk-dotnet3.0-cil/jammy 2.99.3-4build1 amd64

So I manually uninstalled all remaining dotnet packages

$ sudo apt-get remove dotnet-hostfxr-5.0
$ sudo apt autoremove

until the dotnet command was no longer recognized. From this clean state, I ran

$ sudo apt install dotnet6

and got a brand-new dotnet 6 environment and even a new application.

$ dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.109
 Commit:    58a93139d8

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  22.04
 OS Platform: Linux
 RID:         ubuntu.22.04-x64
 Base Path:   /usr/lib/dotnet/dotnet6-6.0.109/sdk/6.0.109/

global.json file:
  Not found

Host:
  Version:      6.0.9
  Architecture: x64
  Commit:       163a63591c

.NET SDKs installed:
  6.0.109 [/usr/lib/dotnet/dotnet6-6.0.109/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.9 [/usr/lib/dotnet/dotnet6-6.0.109/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.9 [/usr/lib/dotnet/dotnet6-6.0.109/shared/Microsoft.NETCore.App]

Fixing Error NU1202: Package Microsoft.EntityFrameworkCore.Tools 6.0.1 is not compatible with netcoreapp2.2 (.NETCoreApp,Version=v2.2)

Migrating an AspNetCore web and database application from version 2.2 to current .Net 6, I came across an occasional build error:

error NU1202: Package Microsoft.EntityFrameworkCore.Tools 6.0.1 is not compatible with netcoreapp2.2 (.NETCoreApp,Version=v2.2). Package Microsoft.EntityFrameworkCore.Tools 6.0.1 supports: net6.0 (.NETCoreApp,Version=v6.0) 

The error went away by unchecking the Option “Allow NuGet to download missing packages” under “Nuget Package Manager”, so I did not bother any longer.

Unfortunately, the error returned as soon as I ran an Azure Build Task on the project. The task failed with a simple message

##[error]Packages failed to restore

without any indication what exactly failed, what was to be restored, and, especially, why.

Going through the log file, I found that nuget tried to restore packages for .Net 6 (good), but also für .NetCore 2.2 (bad):

2022-04-06T13:59:20.3799748Z          Restoring packages for .NETCoreApp,Version=v6.0...
2022-04-06T13:59:20.4022386Z          Resolving conflicts for .NETCoreApp,Version=v2.2...
2022-04-06T13:59:20.4605261Z          Resolving conflicts for net6.0-windows7.0...
2022-04-06T13:59:20.5840720Z          Checking compatibility of packages on .NETCoreApp,Version=v2.2.
2022-04-06T13:59:20.5886337Z          Checking compatibility for microsoft.entityframeworkcore.tools-netcoreapp2.2-[6.0.1, ) 1.0.0 with .NETCoreApp,Version=v2.2.
2022-04-06T13:59:20.6014642Z          Checking compatibility for Microsoft.EntityFrameworkCore.Tools 6.0.1 with .NETCoreApp,Version=v2.2.
2022-04-06T13:59:20.6016218Z      1>D:\DevOpsAgents\some\path\Project.Data.csproj : error NU1202: Package Microsoft.EntityFrameworkCore.Tools 6.0.1 is not compatible with netcoreapp2.2 (.NETCoreApp,Version=v2.2). Package Microsoft.EntityFrameworkCore.Tools 6.0.1 supports: net6.0 (.NETCoreApp,Version=v6.0) 

I also noticed that the first lines of the log stated

Info: .NET Core SDK/runtime 2.2 and 3.0 are now End of Life(EOL) and have been removed from all hosted agents. If you're using these SDK/runtimes on hosted agents, kindly upgrade to newer versions which are not EOL, or else use UseDotNet task to install the required version.
[command]"C:\Program Files\dotnet\dotnet.exe" restore D:\DevOpsAgents\some\path\Project.sln

By that time, I had verified multiple times that the projects do not use any obsolete 2.2 packages anymore. Where does the reference come from?

Then I remembered that I had experienced *some *sort of build errors, as stated above, and tried to run a dotnet restore on my development machine, disabling parallel execution and turning verbosity to full diagnostics:

dotnet restore my.project.sln --disable-parallel -v diag > dotnet-restore.log

The output is huuuge, so I piped it to a file.

Searching the generated log file for netcoreapp2.2, I finally located these lines

17:37:29.274 10:4>_GenerateDotnetCliToolReferenceSpecs: (Target-ID:26)
    TaskParameter:ToolFramework=netcoreapp2.2 (Task-ID: 17)

I found the target _GenerateDotnetCliToolReferenceSpecs in the file C:\Program Files\dotnet\sdk\6.0.101\NuGet.targets, and it sets the DotnetCliToolTargetFramework build variable to a default value if it is not set already. The default value may be, depending on your installation, netcoreapp1.0, netcoreapp2.2, or some other version.

Which part of the project would trigger an action referring to dotnet CLI tools? It’s the EF Core Tools I needed to install for database migrations:

  <ItemGroup>
	  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.1"></DotNetCliToolReference>
  </ItemGroup>

This project setting causes dotnet to install the referenced tool, but fails to do so because the default tool framework is incompatible.

This observed behavior is documented in this GitHub issue for NuGet:

  • The DotnetCliToolTargetFramework will be interpreted by NuGet restore as the maximum target framework that tools can be restored for
  • When restoring .NET CLI tools, NuGet will first download the package, and inspect it to see what it targets. It will choose the maximum target framework the package explicitly supports that is less than or equal to the DotnetCliToolTargetFramework

This GitHub issue showed me how to set the framework version, so I added to my csproj file the following lines:

  <PropertyGroup>
    <DotnetCliToolTargetFramework>net6.0</DotnetCliToolTargetFramework>
  </PropertyGroup>

and dotnet restore worked without errors.

VS Solution Dependency Visualizer supports .NET Core Project Files

When I tried to analyze an unknown Visual Studio solution in my tool VS Solution Dependency Visualizer, I noticed that the project dependencies were not analyzed correctly. In fact, the dependencies were completely ignored.

A bit of research turned up that the solution in question was partly migrated to .NET Core, and the .csproj project files have a slightly different structure than good old .Net project files.

First, the classic .Net project files use a namespace

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

whereas .NET Core project files come without XML namespace, and have the root attribute Sdk:

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

Also, files are not compiled if they are explicitly contained in the .csproj file, but rather by a rule-based Default Compilation mechanism which decides whether files in or below the project directory are compiled, embedded, or ignored.

For a detailed documentation of .NET Core project files, see MS docs or the dotnet GitHub docs.

The latest version of VS Solution Dependency Visualizer with support for .NET Core projects is available for download here.

BTW: In previous versions of this tool, I tried to register VS Solution Dependency Visualizer as an External Tool in all installed versions of Visual Studio.

However, things change all the time, and VS 2013 was the first version that did not support registration via registry, and with VS 2017 things got even more different, and finally I had to give up.

Instructions on how to add VS Solution Dependency Visualizer as an External Tool in your version of Visual Studio can be found in the readme file that comes with the installer.