Search code examples
dockerasp.net-corekubernetes.net-corewwwroot

Static Files in wwwroot not contained in Docker Image


just playing around a little bit. I got a Visual Studio Solution, containing 3 projects. All of the three are needed. One project ("one") is the UI of the application. It contains static files in wwwroot of course.

I want to dockerize the application. The Dockerfile here works. Then I load this image via kubernetes on a Ubuntu Server.

No problem here, the container is running and serving requests.

But it is not serving the static files at all. All these file requests result in a 404 HTTP error. The web site looks like rubbish (but loads, though).

So i logged in to the container and started observing the contents of /app. No directory called "wwwroot" here. Also not the subdirectories. I am not sure, if the wwwroot directory belongs here? Or is the directory included in the dll of the application?

After searching a lot (also found some helpful questions here on StackOverflow), I found out that files are included to the building process automatically. No need to define them separately in the csproj file. But if I do, it results in an error like "Duplicate files included" or something like that.

Here is the Dockerfile:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src
COPY one/one.csproj one/
COPY two/two.csproj two/
COPY three/three.csproj three/
COPY . ./

WORKDIR "/src/one"
RUN dotnet build -c Release -o /app
WORKDIR "/src/two"
RUN dotnet build -c Release -o /app
WORKDIR "/src/three"
RUN dotnet build -c Release -o /app

FROM build AS publish
RUN dotnet publish -c Release -o /app

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

Yes, I am using UseStaticFiles:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }
    // IMPORTANT: This session call MUST go before UseMvc()
    app.UseSession();
    app.UseStaticFiles();
    ...

And the static files are (mostly) all accessed with correct case sensitivity. But as I already said, none of the static files can be accessed.

In the Views, my app includes the CSS files like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="~/framework/1.css">
    <link rel="stylesheet" href="~/framework/2.css" media="screen,projection">
    ...

While, running inside docker, it results in an HTML Output of this:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="/framework/1.css">
    <link rel="stylesheet" href="/framework/2.css" media="screen,projection">
    ...

See the missing tilde ~ ?

How can the static files be included into the docker image?

Thank you! xola


Solution

  • Okay, now I found out myself.

    The error was in the Dockerfile itself. I needed to explicitly say, which csproj file to build and which one to publish. This is what I learned here.

    Actually, no need to define something like "include this file, and this directory" in the csproj file.

    And it is actually important to say, that the wwwroot directory is NOT compiled into the dll. It exists inside the /app folder in the container (that info I couldn't find anywhere, but I got a hint here).

    This also gives the ability to map an external folder to the container (so you can edit the static files without having to re-dockerize it over and over again - of course this is not meant for production environments).

    Also important to say is, that for production environments and generally for all static files you don't want to come into the image (like source SCSS, un-obfuscated JS, temporary files, copies of backups of copies of a file, and so on), a .dockerignore file should be used.

    If you do not, the static files may be accessible directly via the browser, because they come directly into the wwwroot directory.

    So here is my working Dockerfile.

    FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    
    FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
    WORKDIR /src
    COPY all.sln ./    # not sure if I need this
    COPY one/one.csproj one/
    COPY two/two.csproj two/
    COPY three/three.csproj three/
    COPY . ./
    
    RUN dotnet build "/src/one/one.csproj" -c Release -o /app
    RUN dotnet build "/src/two/two.csproj" -c Release -o /app
    RUN dotnet build "/src/three/three.csproj" -c Release -o /app
    
    FROM build AS publish
    RUN dotnet publish "/src/one/one.csproj" -c Release -o /app
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app .
    ENTRYPOINT ["dotnet", "one.dll"]
    

    Hope my explanations help others with this problem in future.

    Thank you! xola