Search code examples
.netdockerdockerfileblazorblazor-webassembly

Dockerfile for .NET 9.0 WASM stand-alone PWA: docker build error at the publish stage


I am new to Docker, but having followed a course (which used Node.js as the app framemwork) and a couple of other tutorials, I have tried to develop an initial test Dockerfile for .NET 9.0 Blazor WASM as a stand-alone PWA, and will attempt to link later to various associated .NET 9.0 APIs I also built. I began with the template from VS 2022, and chose not to include the .csproj file in the solution folder (which is apparently a requirement for .NET Aspire), with no changes to the template project structure, and no new code added, just the basic template itself completely unchanged.

Project structure (as per VS template) is as follows:

docker-test 
    - docker-test
        - bin
            - Debug 
            - Release 
        - Layout
        - obj 
        - Pages
        - Properties
        - wwwroot
        ...
        additional template files including docker-test.csproj (unchanged)
        ...
    - docker-test.sln 
    - Dockerfile

I ran the publish of the project as a first step, as per the instructions at: https://learn.microsoft.com/en-us/dotnet/core/docker/build-container?tabs=windows&pivots=dotnet-9-0

The Dockerfile I have developed by following tutorials and the course is below:

# Dev portion
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR ./
EXPOSE 7149
EXPOSE 5108

# Restore portion
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR ./docker-test
COPY . ./
RUN dotnet restore

# Build portion
WORKDIR ./docker-test
RUN dotnet build ./docker-test.csproj -c $BUILD_CONFIGURATION -o ./build

#Publish portion
FROM build AS publish 
ARG BUILD_CONFIGURATION=Release
WORKDIR ./docker-test/build
RUN dotnet publish -c $BUILD_CONFIGURATION -o ./docker-test/build/publish apphost=false

# Image build portion
FROM base AS final
WORKDIR ./docker-test/build/publish 
COPY --from=publish /docker-test/build/publish .
ENTRYPOINT ["dotnet", "docker-test.dll"]

The error in the terminal states:

ERROR: failed to solve: process "/bin/sh -c dotnet publish -c Release -o ./docker-test/build/publish apphost=false" did not complete successfully: exit code: 1

I have attempted various changes to the specified publish statement itself, and consulted the tutorials and course content again, but not sure where I am making the error (although I'm certain it is a rookie mistake).

Any support with correcting this error so that I can learn how to get it right in future would be extremely appreciated, with thanks in advance for your time.


Solution

  • In your publish step, you have the following

    #Publish portion
    FROM build AS publish 
    ARG BUILD_CONFIGURATION=Release
    WORKDIR ./docker-test/build
    RUN dotnet publish -c $BUILD_CONFIGURATION -o ./docker-test/build/publish apphost=false
    

    In there, you change the work directory from what it was during build, so now it can't find the project file.

    If you keep the same directory and specify the project file like you do on the build command, you should be able to get past the error.

    Another issue is that you use relative paths all the way through the Dockerfile leading to a very deep directory structure at the end. Relative to the starting directory in the build stage, you end up publishing into ./docker-test/docker-test/docker-test/build/docker-test/build/publish which is not what you want. Use absolute paths for the WORKDIRs and maybe relative paths for the output of build and publish.

    Regarding what ports your app listens on, you've EXPOSED ports 7149 and 5108. The EXPOSE statement is mainly documentation for the consumer of an image and in your case, I think the ports are wrong. When you run your application from inside VS, it sets the ports so that might be what you see. But when you run an ASP.NET image from outside VS, it'll listen on port 8080 for HTTP traffic by default. So I'd change the EXPOSE to port 8080. But like I said, it's only documentation, so whatever it says doesn't change the behaviour of the container when you run it.

    With those changes, you should have something like this

    # Dev portion
    FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
    EXPOSE 8080
    
    # Restore portion
    FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
    ARG BUILD_CONFIGURATION=Release
    WORKDIR /docker-test
    COPY . ./
    RUN dotnet restore
    
    # Build portion
    WORKDIR /docker-test/docker-test
    RUN dotnet build ./docker-test.csproj -c $BUILD_CONFIGURATION -o ./build
    
    #Publish portion
    FROM build AS publish 
    ARG BUILD_CONFIGURATION=Release
    # Publish and put output in /docker-test/docker-test/publish
    RUN dotnet publish ./docker-test.csproj -c $BUILD_CONFIGURATION -o ./publish apphost=false
    
    # Image build portion
    FROM base AS final
    WORKDIR /app 
    COPY --from=publish /docker-test/docker-test/publish .
    ENTRYPOINT ["dotnet", "docker-test.dll"]