Dockerfile for a .NET 9 Web API Application
Occasionally, I want to build and run a .NET application within a Docker container.
I use VS Code on Linux, so I don’t have the easy option to add a Dockerfile that is in the full Visual Studio. And I can never remember exactly what to do, so here it is for my future reference.
There are samples on the dotnet/dotnet-docker/
GitHub repo. But it feels a bit cluttered, especially since the .dockerignore
file is easily missed, and critically important.
If you get an error like either of the two below, it’s probably because you copied the obj
directory into the container.
This is very likely to happen on the computer you are developing on because the obj
directory is created when you build or run the application. It is less likely to happen on a build server or CI/CD pipeline because the source code is usually cloned for a repository where the obj
directory should not exist.
error NETSDK1047: Assets file '/source/obj/project.assets.json' doesn't have a target for 'net9.0/linux-x64'. Ensure that restore has run and that you have included 'net9.0' in the TargetFrameworks for your project.
error NETSDK1064: Package Microsoft.AspNetCore.OpenApi, version 9.0.9 was not found. It might have been deleted since NuGet restore. Otherwise, NuGet restore might have only partially completed, which might have been due to maximum path length restrictions.
The project.assets.json
copied has at least two things wrong with it - it has the wrong target framework, and it has absolute paths to your host computer.
The easiest fix is to use a .dockerignore
file to exclude the obj
directory, and any other files/directories you don’t want copied into the container. But it’s easy to forget this step, especially on Linux, because a file starting with a dot is hidden by default.
In a future release of Docker, it should be possible to use an --exclude
option with the COPY
command, but that is not available yet.
A simple, working, but less efficient Dockerfile
But before I show the better way, here is a simple Dockerfile that works. This Dockerfile builds a .NET 9.0 Web API application. It is a little less efficient than it could be, but it does not suffer from the issue described above because the restore happens when publishing. It’s simple and works.
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /source
# Copy everything. This is less efficient
COPY --link . .
# Publish app - will get a warning if there is a .sln file in the directory.
# -c Release is now the default for dotnet publish, but if you are using .NET < 8.0, you should include it.
# A full restore is done as part of the publish.
RUN dotnet publish -c Release -o /app
# Change to the runtime image
FROM mcr.microsoft.com/dotnet/aspnet:9.0
EXPOSE 8080
WORKDIR /app
COPY --link --from=build /app .
ENTRYPOINT ["./WebApiDocker"]
To build it use -
docker build -t webapidocker:1.0 .
To run it, use -
docker run -it --rm -p 8080:8080 webapidocker:1.0
A more efficient Dockerfile, but needs a .dockerignore file
This Dockerfile is more efficient because it restores the NuGet packages before copying the rest of the source code. If you change your source code, but not your dependencies, the restore step will be its own layer and skipped on subsequent builds.
But it does require a .dockerignore
file to skip the obj
directory, and any other files you don’t want copied into the container.
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /source
ARG TARGETARCH
COPY --link ./*.csproj .
RUN dotnet restore -a $TARGETARCH
COPY --link . .
RUN dotnet publish -a $TARGETARCH --no-restore -c Release -o /app
FROM mcr.microsoft.com/dotnet/aspnet:9.0
EXPOSE 8080
WORKDIR /app
COPY --link --from=build /app .
ENTRYPOINT ["./WebApiDocker"]
Here is the .dockerignore
file I use -
**/bin/
**/obj/
**/.vscode/
Dockerfile
.dockerignore
Same commands to build and run as above.