Docker中仅复制C#项目.csproj即可构建依赖的疑问
.NET项目Docker构建疑问解答
提供的文件内容
Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["Ordering.API/Ordering.API.csproj", "Services/Ordering/Ordering.API/"] COPY ["Ordering.Application/Ordering.Application.csproj", "Services/Ordering/Ordering.Application/"] COPY ["Ordering.Core/Ordering.Core.csproj", "Services/Ordering/Ordering.Core/"] COPY ["Ordering.Infrastructure/Ordering.Infrastructure.csproj", "Services/Ordering/Ordering.Infrastructure/"] RUN dotnet restore "Services/Ordering/Ordering.API/Ordering.API.csproj" COPY . Services/Ordering/ WORKDIR "/src/Services/Ordering/Ordering.API" RUN dotnet build "Ordering.API.csproj" -c Release -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release RUN dotnet publish "./Ordering.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "Ordering.API.Containerized.dll"]
docker-compose.yaml片段
ordering.api: image: ${DOCKER_REGISTRY-}orderingapi build: context: . dockerfile: Ordering.API/Dockerfile
疑问点
- 为何仅复制各项目的
.csproj文件到容器,就能找到并纳入所有代码? - 原本以为只有Ordering.API的代码通过
COPY . Services/Ordering/被完整复制,为何该项目仅依靠依赖项目的.csproj文件就能解析所有非Ordering.API项目的代码? dotnet restore难道不应该因为依赖项目的代码未在容器中而失败吗?毕竟仅复制了Ordering.API的代码。- 如果依赖项目的核心代码未导入Docker(仅复制了
.csproj),这些依赖项目的.dll是如何生成的?
解答
1. COPY . Services/Ordering/实际复制了所有项目的代码
你误解了这条指令的作用:Docker构建时的context是当前目录(.),也就是docker-compose里指定的context: .,这个目录包含了所有Ordering相关的项目代码(API、Application、Core、Infrastructure)。所以COPY . Services/Ordering/是把本地所有代码都复制到容器内的/src/Services/Ordering/目录下,并非只复制Ordering.API的代码。
2. 先复制.csproj是为了利用Docker缓存优化构建速度
先单独复制各项目的.csproj文件,然后执行dotnet restore,这是Docker构建.NET项目的标准优化手段:
.csproj文件的变更频率远低于代码文件,当代码修改但项目依赖未变时,Docker会复用之前dotnet restore的缓存层,不需要重新下载NuGet包,大幅加快构建速度。- 如果一开始就复制所有代码,那么任何代码改动都会导致
dotnet restore重新执行,浪费时间。
3. dotnet restore和dotnet build的工作逻辑
dotnet restore只需要.csproj文件就能解析项目依赖(包括项目间引用和NuGet包),它的作用是下载所需的NuGet包到容器内的缓存目录,不需要项目的实际代码。- 当执行
COPY . Services/Ordering/后,所有项目的代码都已经在容器里了,后续的dotnet build会编译所有相关项目:因为Ordering.API的.csproj里引用了Ordering.Application,而Ordering.Application又引用了Core和Infrastructure,dotnet build会自动找到这些项目的代码(已经复制到对应路径)并编译生成各自的.dll,最终打包到Ordering.API的发布产物中。
简单来说,整个流程是:
- 复制所有项目的
.csproj→ 执行restore下载NuGet包(利用缓存) - 复制所有项目的代码 → 执行build编译所有依赖项目 → 执行publish生成可部署的产物
内容的提问来源于stack exchange,提问作者toto'
相关产品推荐
相关产品推荐

