Search code examples
c#dockerasp.net-core.net-core

Cannot locally browse to index.html when running API project in Docker container


I'm trying to set up my .NET API to run in a Docker container and be accessible via my browser. I'm having trouble when running for local development. The repo (on the dev branch specifically) is here.

My API was previously set up to run alongside a UI project, which ran by default when I started the application, but I'm working on removing that (you can see that commented out in the csproj file for the API here). I've added a wwwroot to the rardk.web.API project, and I've unloaded the rardk.web.UI project, but I don't seem to get my test HTML page when running the API project as the startup project.

Here's my Dockerfile:

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["rardk.web.UI/nuget.config", "rardk.web.UI/"]
COPY ["rardk.web.API/rardk.web.API.csproj", "rardk.web.API/"]
COPY ["rardk.web.BusinessLayer/rardk.web.BusinessLayer.csproj", "rardk.web.BusinessLayer/"]
COPY ["rardk.web.ServiceLayer/rardk.web.ServiceLayer.csproj", "rardk.web.ServiceLayer/"]
COPY ["rardk.web.Models/rardk.web.Models.csproj", "rardk.web.Models/"]
# COPY ["rardk.web.UI/rardk.web.UI.esproj", "rardk.web.UI/"]
RUN dotnet restore "./rardk.web.API/./rardk.web.API.csproj"
COPY . .
WORKDIR "/src/rardk.web.API"
RUN dotnet build "./rardk.web.API.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./rardk.web.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "rardk.web.API.dll"]

and my launchSettings.json

{
  "profiles": {
    "http": {
      "commandName": "Project",
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5227"
    },
    "https": {
      "commandName": "Project",
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "https://localhost:7042;http://localhost:5227"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Docker": {
      "commandName": "Docker",
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
      "environmentVariables": {
        "ASPNETCORE_HTTPS_PORTS": "8081",
        "ASPNETCORE_HTTP_PORTS": "8080"
      },
      "publishAllPorts": true,
      "useSSL": true
    }
  },
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:36857",
      "sslPort": 44319
    }
  }
}

These are the logs in my container, including the 404s when I tried to browse to it:

2024-01-07 11:44:56 [16:44:56 INF] Now listening on: http://[::]:8080
2024-01-07 11:44:56 [16:44:56 INF] Now listening on: https://[::]:8081
2024-01-07 11:44:56 [16:44:56 INF] Application started. Press Ctrl+C to shut down.
2024-01-07 11:44:56 [16:44:56 INF] Hosting environment: Development
2024-01-07 11:44:56 [16:44:56 INF] Content root path: /app
2024-01-07 11:45:09 [16:45:09 INF] Request starting HTTP/1.1 GET http://localhost:32771/ - null null
2024-01-07 11:45:10 [16:45:10 INF] Request finished HTTP/1.1 GET http://localhost:32771/ - 307 0 null 130.1059ms
2024-01-07 11:45:10 [16:45:10 INF] Request starting HTTP/2 GET https://localhost:32770/ - null null
2024-01-07 11:45:10 [16:45:10 INF] Request finished HTTP/2 GET https://localhost:32770/index.html - 404 0 null 69.0943ms
2024-01-07 11:45:10 [16:45:10 INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET https://localhost:32770/index.html, Response status code: 404
2024-01-07 11:45:50 [16:45:50 INF] Request starting HTTP/1.1 GET http://localhost:32771/ - null null
2024-01-07 11:45:50 [16:45:50 INF] Request finished HTTP/1.1 GET http://localhost:32771/ - 307 0 null 1.7569ms
2024-01-07 11:45:50 [16:45:50 INF] Request starting HTTP/2 GET https://localhost:32770/ - null null
2024-01-07 11:45:50 [16:45:50 INF] Request finished HTTP/2 GET https://localhost:32770/index.html - 404 0 null 84.2565ms
2024-01-07 11:45:50 [16:45:50 INF] Request reached the end of the middleware pipeline without being handled by application code. Request path: GET https://localhost:32770/index.html, Response status code: 404

Solution

  • You are running the docker container in the development mode (from the logs):

    2024-01-07 11:44:56 [16:44:56 INF] Hosting environment: Development

    But you are serving static files only for non-development environments:

    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    else
    {
        app.UseDefaultFiles();
        app.UseStaticFiles(); // <- here
    }
    

    So the index.html from wwwwroot will not be served in the Development one. Just remove the else and add static files unconditionally:

    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.UseDefaultFiles();
    app.UseStaticFiles();