Reputation: 489
I'm playing with docker and .NET Core 3 using Visual Studio 2019. I containerize my application by adding the Dockerfile to my project (right click on the project -> Add -> Docker Support) and I was able to launch it, but now I want to use dotnet watch run
inside the container.
This is the generated 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 ["DockerTestApp/DockerTestApp.csproj", "DockerTestApp/"]
RUN dotnet restore "DockerTestApp/DockerTestApp.csproj"
COPY . .
WORKDIR "/src/DockerTestApp"
RUN dotnet build "DockerTestApp.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "DockerTestApp.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "DockerTestApp.dll"]
and I modified it like so:
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
WORKDIR /src
EXPOSE 80
EXPOSE 443
COPY ["DockerTestApp/DockerTestApp.csproj", "DockerTestApp/"]
RUN dotnet restore "DockerTestApp/DockerTestApp.csproj"
ENTRYPOINT ["dotnet", "watch", "run"]
The container started with dotnet watch run
but any file change isn't detected and the rebuild is not triggered.
Should I have to mount a volume from my code directory to the container in order to make it work?
Thanks.
UPDATE
with this Dokerfile
FROM mcr.microsoft.com/dotnet/core/sdk:3.0
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
WORKDIR /app
COPY . .
ENTRYPOINT dotnet watch run --urls=https://+:5001 --project DocketTestApp.csproj
and this docker-compose.yml
version: '3.4'
services:
dotnet-watch-docker-example:
container_name: dotnet_watch_docker_example
image: giuseppeterrasi/dotnet-watch-docker-example
build:
context: ./DocketTestApp/
ports:
- 5001:5001
volumes:
- './DocketTestApp/:/app/'
depends_on:
- db
db:
image: mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: testPassword
MYSQL_DATABASE: testDB
MYSQL_USER: testUser
MYSQL_PASSWORD: test
It works, but if I add a DbContext, Visual Studio misses the Entity Framework reference if the container is started. If I stop the container and reload Visual Studio everything is ok.
Why?
UPDATE 2023
With Visual Studio 2022 17.7 or later this is fully supported out of the box! GitHub issue reference
Upvotes: 12
Views: 10001
Reputation: 1869
Files inside the obj/
and the bin/
folders have to be different on your local machine and inside the Docker container. If they overlap, you’ll get errors.
To resolve that issue, you can change the location of the obj/
and bin/
as
@Mike Hawkins explained.
But there is also an another solution.
Bind mount volume override your docker bin/
and obj/
directories with local bin/
and obj/
, to avoid this overriging, you have to tell docker that bin/
and obj/
folders shouldn't be overwritten from outside. That can be achived with another (anonymous) volume. Docker evaluates all your volumes and if they are overlapping, the longer internal path is leading the way.
You can define this volume in the Dockerfile
VOLUME ["/app/path/to/bin"]
VOLUME ["/app/path/to/obj"]
Or in the docker-compose
volumes:
- ./DockerTestApp:/app
- /app/path/to/bin
- /app/path/to/obj
The disadvantage of this approach is need of explicitly typing all bin/
and obj/
folder paths from the entire solution.
Upvotes: 0
Reputation: 2304
You can omit using a custom Dockerfile when you want to run dotnet watch run
locally.
Consider the following docker-compose.yml file:
version: '3.4'
services:
dotnet-watch-docker-example:
container_name: dotnet_watch_docker_example
image: mcr.microsoft.com/dotnet/core/sdk:3.0
ports:
- 5001:5001
volumes:
- ./DockerTestApp:/app
working_dir: /app
command: dotnet watch run
Instead of creating a custom image from the base dotnet sdk image, the compose file simply starts a container based on the base dotnet sdk image. It then creates a volume that maps the local directory containing your project to the directory /app inside the container. It then sets the working directory inside the container to /app, and lastly, it runs the dotnet watch run command inside the container.
To fix your problem with the Entity framework reference, add the following Directory.Build.props file inside the project directory. This file instructs MSBUILD to place /bin and /obj files in different directories (container/local) dependent upon the executing environment. This way, no conflicts emerge.
<Project>
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/obj/**/*</DefaultItemExcludes>
<DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/bin/**/*</DefaultItemExcludes>
</PropertyGroup>
<PropertyGroup Condition="'$(DOTNET_RUNNING_IN_CONTAINER)' == 'true'">
<BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/container/</BaseIntermediateOutputPath>
<BaseOutputPath>$(MSBuildProjectDirectory)/bin/container/</BaseOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(DOTNET_RUNNING_IN_CONTAINER)' != 'true'">
<BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/local/</BaseIntermediateOutputPath>
<BaseOutputPath>$(MSBuildProjectDirectory)/bin/local/</BaseOutputPath>
</PropertyGroup>
</Project>
Upvotes: 9
Reputation: 202
Change the entry point like this,
ENTRYPOINT dotnet watch run --no-restore
This will rebuild the server whenever new changes occurs.
Upvotes: 3