如何在.Net Core 3、Visual Studio 2019和Docker中使用"dotnet watch run"命令

12
我正在使用Visual Studio 2019玩docker和.NET Core 3。我通过将Dockerfile添加到我的项目中(右键单击项目->添加->Docker支持)来容器化我的应用程序,我能够启动它,但现在我想在容器内使用dotnet watch run
这是生成的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"]


我对它进行了修改,像这样:
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"] 

容器是通过dotnet watch run启动的,但是无法检测到任何文件更改,也不会触发重新构建。

我是否需要将我的代码目录挂载到容器中才能使其正常工作?

谢谢。

更新

使用这个Dockerfile

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


这个 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

它可以工作,但是如果我添加了一个DbContext,当容器启动时,Visual Studio会丢失Entity Framework的引用。如果我停止容器并重新加载Visual Studio,一切都正常。

为什么会这样?

2023年更新

使用Visual Studio 2022 17.7或更高版本,这个问题已经完全支持!GitHub问题参考

3个回答

9

当您想在本地运行 dotnet watch run 时,可以省略使用自定义 Dockerfile。

考虑以下的 docker-compose.yml 文件:

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

不需要从基础的dotnet sdk镜像创建自定义镜像,compose文件仅启动一个基于基础dotnet sdk镜像的容器。然后创建一个卷将包含项目的本地目录映射到容器内的/app目录, 接着设置容器内的工作目录为/app并最后在容器内运行dotnet watch run命令。

为了解决Entity Framework引用的问题,请在项目目录下添加以下Directory.Build.props文件。该文件指示MSBUILD将/bin和/obj文件放置在不同的目录(容器/本地)取决于执行环境,以避免冲突。

<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>

谢谢您的回复。我已经测试过了,obj/container和obj/local这两个目录都被正确地创建了。第一个目录是在启动docker-compose up时创建的,第二个目录是在Visual Studio构建解决方案时创建的。但是当docker正在运行时,Visual Studio仍然缺少EntityFramework引用。 - Giuseppe Terrasi
1
尝试删除引用EntityFramework的项目中的obj/和bin/文件夹,然后重新打开Visual Studio。 - Mike Hawkins
2
在我删除了初始的 obj 和 bin 目录并重新启动 Omnisharp 后,这对我完美地起作用了。 - Zac Ball
1
@ZacBall 很高兴听到这个消息! - Mike Hawkins

3

将入口点更改为以下内容:

ENTRYPOINT dotnet watch run --no-restore

每当发生新变化时,这将重新构建服务器。

1
谢谢您的回复,但它不起作用,仍然没有检测到任何更改。 - Giuseppe Terrasi

0

obj/bin/文件夹中的文件必须在您的本地机器和Docker容器内部不同。如果它们重叠,您将会遇到错误。

为了解决这个问题,您可以像@Mike Hawkins所解释的那样更改obj/bin/的位置。

但是还有另一种解决方案。

绑定挂载卷会覆盖您的docker bin/obj/目录与本地bin/obj/,为了避免这种覆盖,您必须告诉dockerbin/obj/文件夹不应该被外部覆盖。这可以通过另一个(匿名)卷来实现。Docker评估所有卷,如果它们重叠,较长的内部路径将引导前进。

您可以在Dockerfile中定义此卷。

VOLUME ["/app/path/to/bin"]
VOLUME ["/app/path/to/obj"]

或者在docker-compose中

    volumes:
      - ./DockerTestApp:/app
      - /app/path/to/bin
      - /app/path/to/obj

这种方法的缺点是需要显式地键入整个解决方案中所有 bin/obj/ 文件夹路径。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接