'How can I target multiple .NET Core versions from a single Docker image?

I have a library that targets .NET Standard 2.0. To verify compatibility, I would like to run my unit tests with the current and long term support (LTS) versions of .NET Core. When this question was written, those were:

Target Framework Target framework moniker (TFM)
.NET 5.0 (current) net5.0
.NET Core 3.1 (LTS) netcoreapp3.1
.NET Core 2.1 (LTS) netcoreapp2.1

It's easy enough to set up the csproj files to target multiple frameworks:

<PropertyGroup>
  <TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
</PropertyGroup>

That works well for local builds when all of these SDKs are installed. However, I'd prefer to have my CI builds take place on a single, lightweight Docker container. I'm not worried about verifying .NET Framework support, so I don't need Windows. The .NET SDK images on Docker Hub work well for any single framework (i.e., mcr.microsoft.com/dotnet/sdk:5.0), but I would like to find a Docker image that includes all three of these SDKs without the baggage of a "kitchen sink" image like the GitHub-hosted runners, which include many unrelated frameworks and tools.

I could write my own Dockerfile, starting from a base image and scripting the installation of the extra SDKs, but surely I can't be the only person who could use something like this. Does a suitable Docker image already exist somewhere? Should I be taking a different approach to this problem, like scripting the SDK installation with setup-dotnet or an equivalent?



Solution 1:[1]

Just use the Docker image for the latest .NET version (currently mcr.microsoft.com/dotnet/sdk:5.0). It's capable of building projects that target different versions. It's the same as how you can do this locally on your dev machine. You can just install 5.0 SDK on your machine and build projects that target 2.1, 3.1, or 5.0.

If you're wanting to run unit tests in the same container, you will need to install the extra runtimes that you require for each of the versions other than 5.0. This will vary based on what OS you're targeting but you can find details on the installation at https://docs.microsoft.com/en-us/dotnet/core/install/. For example, on Debian, you can install ASP.NET 3.1 runtime with the following:

wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && \
dpkg -i packages-microsoft-prod.deb && \
apt-get update && \
apt-get install -y apt-transport-https && \
apt-get update && \
apt-get install -y aspnetcore-runtime-3.1

Solution 2:[2]

I've tried to avoid building custom images and scripting extra runtimes, so my variant was to run build/test on multiple containers (sdk:2.1, sdk:3.1) separately.

Funny enough, having multitarget:

<PropertyGroup>
  <TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>

does not allow building on sdk:2.1 container, even if you specify that you only want to build for 2.1, with parameter -f netcoreapp2.1.

I ended up with conditioned csproj file, which specifies TargetFrameworks based on outside parameter. For example, my csproj configuration is:

<TargetFrameworks Condition=" '$(TestTargetFramework)' == '' ">netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks Condition=" '$(TestTargetFramework)' == 'netcoreapp2.1' ">netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(TestTargetFramework)' == 'netcoreapp3.1' ">netstandard2.1</TargetFrameworks>

And I can build/test it on sdk:2.1:

dotnet test ./test/Tests --configuration Release /p:TestTargetFramework=netcoreapp2.1

Or sdk:3.1:

dotnet test ./test/Tests --configuration Release /p:TestTargetFramework=netcoreapp3.1

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Matt Thalman
Solution 2 Algirdas