Picture: Docker Inc.

Run ASP.NET Core with .NET Framework in a Docker Container

Sometimes you still have the requirement that the .NET Framework is needed - but you still want to use ASP.NET Core and Docker.

Future of ASP.NET Core and .NET Framework

ASP.NET Core offers the possibility that both .NET Core and the .NET Framework can be used. But this could change with ASP.NET Core 3: actually Microsoft had the plan that already from ASP.NET Core 2.0 only .NET Core is supported.

However, the community was very critical of GitHub, which has led Microsoft to continue to support the .NET Core and .NET Framework in ASP.NET Core. I would expect, that with ASP.NET Core 3.0 only .NET Core will be supported as runtime - although more information is not public yet.

ASP.NET Core and Docker

Microsoft maintains the Docker images around ASP.NET Core very well and very quickly. There are images for .NET Core and .NET Framework. However, there is no image that includes both the .NET Core and the .NET Framework. Microsoft justifies this with an oversized image.

Nevertheless, you can use ASP.NET Core with the .NET Framework! In this case, .NET Core is not even needed.

ASP.NET with .NET Framework

In order to use ASP.NET Core with the .NET Framework, the. csproj file must be edited first.

Change

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

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

to

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

  <PropertyGroup>
    <TargetFramework>net461</TargetFramework> <!-- or your .NET Framework version -->
    <DockerTargetOS>Windows</DockerTargetOS>
  </PropertyGroup>

This causes the application no longer will be built as an assembly, which can be started with dotnet <assemblyname.dll>, instead it creates an EXE file that can be executed directly.

Note that the .NET Framewrk version of the application is also campatible with the .NET Framework version of the Docker image. There exist different versions.

Build the application

In order for the content of the application to end up in the Docker image, the content must first be created.

I am counting on the principle that I create the application first and copy the files later into the Docker image. The reason for this is that a NuGet restore against a private feed requires credentials; and I don't want to see them directly in my build definition or even the container history.

Therefore, it is easier to create the content outside and then simply copy it when you create the Docker image.

So I use the following PowerShell script

Remove-Item .\_artifacts -Force -Recurse -ErrorAction SilentlyContinue
dotnet publish applicationname.csproj -c Release -o _artifacts/appfiles

This publishes my application and copies the content into the folder _artifacts/files.

The Dockerfile

I can now use these files to create the Docker image of my application.

The Docker file is based on the image microsoft/dotnet-framework:4.7.2-runtime-windowsservercore-1803, which has already integrated the .NET Framework version 4.7.2.

I don't need NET Core or .NET CLI functionality because I have created an EXE. The EXE can be used as entrypoint to start the application when the container starts.

The additional environment variables of ASP.NET Core now ensure that the port mapping is correct and the application listens to port 80 inside the container.

# escape=`

# use .NET Framework image with WindowsServerCore
FROM microsoft/dotnet-framework:4.7.2-runtime-windowsservercore-1803
WORKDIR /app
# copy published application files inside the image
COPY _artifacts/appfiles /.

# configure web servers to bind to port 80 when present
ENV ASPNETCORE_URLS=http://+:80 `
    # Enable detection of running in a container
    DOTNET_RUNNING_IN_CONTAINERS=true `
    # ignore first time expierence
    DOTNET_SKIP_FIRST_TIME_EXPERIENCE="true"

# start the exe on container startup
ENTRYPOINT ["ApplicationName.exe"]

Start the container

Now the Docker container can be started.

However, I always create the Docker container manually before I start the container. This makes it in my eyes easier to set certain settings such as the port mapping or the container name.

Create the container with

docker container create --name <yourcontainername> --publish 31337:80 <yourdockername>/<yourapplicationimagename>:dev

Start the container with

docker start <yourcontainername> 

Docker Image with .NET Core and .NET Framework

Because Microsoft does not provide an image with built-in .NET Framework and .NET Core, it must be created by yourself - if required.

# escape=`

# .NET Core image to copy that stuff
FROM microsoft/dotnet:2.1-sdk-nanoserver-1803 AS dotnet

# Windows Server image with .NET Framework image as base
FROM microsoft/dotnet-framework:4.7.2-runtime-windowsservercore-1803

# copy the .NET Core stuff from the .NET Core Image to the Windows Server Image
ENV DOTNET_PATH="C:\Program Files\dotnet" 
COPY --from=dotnet ${DOTNET_PATH} ${DOTNET_PATH}

# set environment path with .NET Core
RUN $env:PATH = $env:DOTNET_PATH + ';' + $env:PATH; `
    [Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine)

# Configure web servers to bind to port 80 when present
ENV ASPNETCORE_URLS=http://+:80 `
    # Enable detection of running in a container
    DOTNET_RUNNING_IN_CONTAINERS=true `
    # ignore first time expierence
    DOTNET_SKIP_FIRST_TIME_EXPERIENCE="true"

Now this image can be used as base that includes both .NET Core and the .NET Framework. It's about 5GB in size - not light-weight anymore.