multiple asp.net core project have problems in docker - c#

I used Visual Studio 2019 and created my dockerfile with it.
my docker file
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["BackEnd.service.api.csproj", "BackEnd.service.api"]
COPY ["src/BackEnd.Service.Application/BackEnd.Service.Application.csproj", "src/BackEnd.Service.Application/"]
COPY ["src/BackEnd.Service.Model/BackEnd.Service.Model.csproj", "src/BackEnd.Service.Model/"]
RUN dotnet restore "src/BackEnd.service.api/BackEnd.service.api.csproj"
COPY . .
WORKDIR "/src/src/BackEnd.service.api"
RUN dotnet build "BackEnd.service.api.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "BackEnd.service.api.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "BackEnd.service.api.dll"]
and my project tree:
now I have this error:
please help me to how can I change my route of project to build it in docker?

The problem is most likely your build context. Visual Studio seems to be using you web app project as the build context, meaning it can't access your Application and Model projects from the src folder.
I can suggest that you try to explicitly set the Dockerfile context in your web app's .csproj file with the following property to the src directory from which all projects are accessible:
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<DockerfileContext>..\</DockerfileContext>
</PropertyGroup>
Then you may need to update your Dockerfile to point to your reference projects (Application and Model) to be relative towards the src folder.
COPY ["BackEnd.service.api/BackEnd.service.api.csproj", "src/BackEnd.service.api"]
COPY ["BackEnd.Service.Application/BackEnd.Service.Application.csproj", "src/BackEnd.Service.Application/"]
COPY ["BackEnd.Service.Model/BackEnd.Service.Model.csproj", "src/BackEnd.Service.Model/"]
RUN dotnet restore "src/BackEnd.service.api/BackEnd.service.api.csproj"
You may need to play around with the directories a bit, but its very important to remember that the build context is the key.
Alternatively you can try to add a docker-compose project to your solution and have that build your Dockerfile. You will be able to specify a build context in the docker-compose.yml file for each project that should be built.

I suggest follow this article aspnetcore-app-dockerfiles to make dockerfile manually instead of vs project's docker template. Also, use .dockerignore will help you simplify your dockerfile script, ignore files might not need runtime.
Here is an example from my project, hope helps.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-bionic AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-bionic AS build
WORKDIR /build
COPY . .
RUN dotnet restore
RUN dotnet publish "src/BackEnd.service.api/BackEnd.service.api.csproj" -c Release -o /app --no-restore
FROM base AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "BackEnd.service.api.dll"]

Related

What is the problem when reciving MSB1001: Unkown switch, when trying to publishing C# application?

I am trying to dockerize my web API with docker and I have encountered an error MSB1001: Unkown switch. More details can be found in the cmd prompt image
Does anyone know what this means, I've tried to follow up on this in GitHub discussions and posts in StackOverflow.
My Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR C:\Users\Alexa\OneDrive\Desktop\SortIT\Api
# Copy everything
COPY . .
# Restore as distinct layers
RUN dotnet restore "./Api.csproj"
RUN dotnet publish "/Api.csproj" -c release -o ./
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
COPY --from=build /Api .
ENTRYPOINT ["dotnet", "Api.dll"]
My file directory
There are a number of issues with your Dockerfile. The one giving you the 'unknown switch' is on the publish statement, where you've given the project file name as /Api.csproj. It should be ./Api.csproj.
As others have pointed out, your WORKDIR uses Windows syntax, but you're building a Linux image and should use Linux syntax. I like to use /src as the directory in my build steps.
You publish the project to ./ which means that you'll end up with a directory that contains both your source and the published project. You want to keep them separate, so you can copy only the published project into the final image.
Which those changes, you end up with
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
# Copy everything
COPY . .
# Restore as distinct layers
RUN dotnet restore "./Api.csproj"
RUN dotnet publish "./Api.csproj" -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
COPY --from=build /src/out .
ENTRYPOINT ["dotnet", "Api.dll"]
I assume you have build context in the folder with Api.csproj file. First - WORKDIR sets the current working directory in the container. It is not a directory on the host system. You start with a directory where you copy source code from the build context to the container. Good name for it /src
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src # current directory in the container
COPY . . # Copy everything from build context to /src
RUN dotnet restore "Api.csproj"
Note that in order to optimize the build process and use caching, its better to start with copying *.csproj file only and restore dependencies. Because source code changes more often then dependencies of the application.
Next you want to build/publish your application somewhere in a container. Usually you create new directory for that and don't use the system root:
#publish app to folder /publish
RUN dotnet publish "Api.csproj" -c release -o /publish
And the last step - you should copy the published application to the runtime container. Here you set the current directory to the directory where the published application will be located:
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app #now set the current directory to /app
COPY --from=build /publish . #copy from build stage to /app
And don't forget to expose ports used by your API.
Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY "Api.csproj" .
RUN dotnet restore "Api.csproj"
COPY . .
RUN dotnet publish "Api.csproj" -c release -o /publish
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
EXPOSE 80
COPY --from=build /publish .
ENTRYPOINT ["dotnet", "Api.dll"]

Why restore and build are needed before publish in dockerfile autogenerated for .NET Core by VisualStudio

VisualStudio generates Dockerfile for .NET Core like this:
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["src/Sandbox/Sandbox.csproj", "src/Sandbox/"]
RUN dotnet restore "src/Sandbox/Sandbox.csproj"
COPY . .
WORKDIR "/src/src/Sandbox"
RUN dotnet build "Sandbox.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Sandbox.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Sandbox.dll"]
There are three different steps with SDK there:
restore
build
publish
It looks like it can be simplified to one publish stage and get something like this:
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS publish
WORKDIR /src
COPY . .
RUN dotnet publish "src/Sandbox/Sandbox.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Sandbox.dll"]
Is this separation in steps necessary to make it easier to customize each step in the future, or is there any other reason to do so?
It looks like they are trying to optimize things - by using docker caching and layering.
Splitting off restore from build/publish is a good idea. Your code changes often, but your project files and dependencies change little. Docker uses caching for things that don't change. If you can separate your project file from the rest of your code, you can cache the "restore" operation and make future builds faster.
See build caching in the docker docs for more information about how this works.
Also take a look at this: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/docker/building-net-docker-images?view=aspnetcore-5.0#the-dockerfile
I am not sure what this gets you:
RUN dotnet build "Sandbox.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Sandbox.csproj" -c Release -o /app/publish
I feel like the publish could be combined into the previous stage. I must be missing something.
Edit: On further thinking, perhaps this lets you use the cache (again!) while customizing how you publish?
For example, if you wanted to publish in self-contained mode, or target a different runtime id, you would just have to change the publish command and not the build command. If your application is large, that might save you some time.
Splitting into restore, build, and publish steps provides better caching of docker images at each of these steps.
For example, if the csproj file has not been modified, the cached image is used for the restore step instead of building a new one:
CACHED [build 4/7] RUN dotnet restore "src/Sandbox/Sandbox.csproj"
The same can be applied to the build step as long as there are no changes in all source files:
CACHED [build 7/7] RUN dotnet build "Sandbox.csproj" -c Release -o /app/build

Fail to create DockerFile - copy error, project not found

Fail to create DockerFile (Linux target) which was generated automatically using VS2019 -> add docker support,
my project structure is:
D:\MasterProjects\WebApi\WebApi\WebApi.csproj
D:\MasterProjects\Proj1\Proj1\Proj1.vbproj
D:\MasterProjects\Proj1\Proj2\Proj2.vbproj
In the WebApi project, there is a reference to Proj1
In the Proj1 project, there is a reference to Proj2
I've tried to add also a copy section to the third project (Proj2) without any luck,
tried also to run the docker file from the sln folder (changing the copy path), also no luck
my docker file located in D:\MasterProjects\WebApi\WebApi
I get a copy error on the second project which can't be found
the docker file content is:
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
WORKDIR /src
COPY ["WebApi.csproj", "WebApi/"]
COPY ["../Proj1/Proj1/Proj1.vbproj", "../Proj1/Proj1/"]
RUN dotnet restore "WebApi/WebApi.csproj"
COPY . .
WORKDIR "/src/WebApi"
RUN dotnet build "WebApi.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebApi.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApi.dll"]````

ASP.NET Core Web App appsettings.json values replaced by random strings in docker container

I have an ASP.NET Core web app that has some values stored in appsettings.json which are being accessed through the IConfiguration service.
This works fine when the app is published and hosted in IIS on a windows machine. However when running in a linux docker container the values in appsettings are replaced with random strings such as 7d5136967af41.
The appsettings file is set to always copy to the output directory
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
I'm not sure where this problem is coming from so I will add the docker file too
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["ProjectName/ProjectName.csproj", "ProjectName/"]
RUN dotnet restore "ProjectName/ProjectName.csproj"
COPY . .
WORKDIR "/src/ProjectName"
RUN dotnet build "ProjectName.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "ProjectName.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["dotnet", "ProjectName.dll"]
There are no errors when running docker build -t imagename -f ProjectName/Dockerfile . and no errors in the docker container logs
If any other files are need let me know and I will add them too, any help is greatly appreciated
Thanks
For anyone who comes across this issue too, it seems that using an appsetting of "Hostname" was the issue for, changing the name to anything else resolved the issue for me
Hope this helps

How to build one docker image for multiple projects?

In my project I am using .net core 2.2 , recently I am using additional class library inside my project.
When I am trying to build my image it can not found my dll.
My docker file looks like:
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
EXPOSE 80
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "LibvirtManagement.dll"]
I am getting error like this:
The project file "/JenkinsService/JenkinsService.csproj" was not found.
[/app/LibvirtManagement.sln]
The command '/bin/sh -c dotnet publish -c Release -o out' returned a non-zero code: 1
The error message is pretty straightforward, you're missing JenkinsService.csproj and other files from this project in docker container where you build it. You need to copy these files as well.
If you're using Visual Studio the easiest way to do it is to right-click executable project file (LibvirtManagement in your case) and then select Add -> Docker Support.... It will auto-generate correct Dockerfile for you
EDIT: this is what this tool created for me:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["LibvirtManagement/LibvirtManagement.csproj", "LibvirtManagement/"]
COPY ["JenkinsService/JenkinsService.csproj", "JenkinsService/"]
RUN dotnet restore "LibvirtManagement/LibvirtManagement.csproj"
COPY . .
WORKDIR "/src/LibvirtManagement"
RUN dotnet build "LibvirtManagement.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "LibvirtManagement.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "LibvirtManagement.dll"]

Categories

Resources