Static Files in wwwroot not contained in Docker Image
Asked Answered
S

3

11

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

Sihonn answered 24/2, 2020 at 16:1 Comment(2)
I've never seen ~ used in a path before, what's the purpose? If you want a relative path to the file you're running, use . instead: "./framework/1.css"Allinclusive
I understand. Since it works when I compile it locally, I didn't care about that. This may not solve the problem, right?Sihonn
S
9

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

Sihonn answered 25/2, 2020 at 9:20 Comment(3)
Hey, how did you "say, that the wwwroot directory is NOT compiled into the dll"? I have this exact problem, I can use the controllers, but the files in wwwroot are not served.Pigling
@Pigling I'm having the same issue, plz tell me if u solve it ;(Eirene
A part of this answer helped me - "wwwroot is not compiled into the dll". I was under the impression that it will be compiled into the dll and so I added wwwroot to my gitignore. When the build was triggered via CI and deployed, all my static files were missing. Fixed it by removing the wwwroot from .gitignore.Boehike
B
0

To fix this problem, just add this XML code to your ASP.NET Core web project .csproj file inside your <ItemGroup> node. I would place this code after your list of nuget packages as shown below. This code will copy your static folder and all its subfolders and files to your Docker image when its compiled. No need to change your dockerfile.

<ItemGroup>
    <PackageReference.........

    <Content Include="MySubFolder\*">
        <CopyToPublishDirectory>always</CopyToPublishDirectory>
    </Content>
</ItemGroup>
Bulbil answered 15/2, 2023 at 20:21 Comment(0)
N
0

If someone stumbles upon here, this is my approach for a .net7 asp core hosted blazor wasm app, my wwwroot was empty so i moved the publish output to app instead of root:

# Backend building
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /
# Copy everything
COPY ./ ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish /Server/HeimKinoTron.Server.csproj -c Release -o app
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app # crucial so the wwwroot is not resettet somehow.
COPY --from=build /app .
RUN chown -R 1000:1000 ./wwwroot
ENTRYPOINT ["dotnet", "./HeimKinoTron.Server.dll"]
Natalee answered 23/10, 2023 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.