This chapter explores the build system in depth, CI/CD pipeline integration, Docker containerization, and the various deployment models available for .NET Core applications.
MSBuild is the build engine behind .NET Core. Every .csproj file is an MSBuild project file. You can extend the build pipeline with custom targets.
<Target Name="PostBuild" AfterTargets="Build">
<Copy SourceFiles="$(OutputPath)$(AssemblyName).dll"
DestinationFolder="$(SolutionDir)dist/"/>
</Target>
Override the built-in BeforeBuild and AfterBuild targets to inject pre- or post-processing logic:
<Target Name="BeforeBuild">
<Message Importance="high" Text="Building $(ProjectName)..." />
</Target>
Common properties: OutputType, TargetFramework, AssemblyName, RootNamespace. Items like Compile, Content, EmbeddedResource define what gets built.
Modern teams automate builds and deployments using continuous integration and delivery pipelines.
name: .NET Core Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --no-restore -c Release
- name: Test
run: dotnet test --no-build -c Release
- name: Publish
run: dotnet publish -c Release -o artifacts
trigger:
- main
pool: ubuntu-latest
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'test'
arguments: '--configuration Release'
Containerizing .NET apps is straightforward with multi-stage Dockerfiles:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app .
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]
aspnet image for ASP.NET Core apps and the smaller runtime image for console apps. Consider Alpine-based images for smaller footprints.Framework-dependent deployment (FDD) requires the .NET runtime on the target machine. It produces smaller deployments.
Self-contained deployment (SCD) bundles the runtime and framework libraries together. Larger but entirely independent.
dotnet publish --self-contained true --runtime win-x64
dotnet publish --self-contained false # Default
Packages the entire application into a single executable:
dotnet publish -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
R2R compiles IL to native code at publish time, reducing JIT overhead at startup:
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=true
Publish trimming removes unused assemblies to reduce deployment size:
dotnet publish -p:PublishTrimmed=true -p:TrimMode=Link
linux-x64, and builds a Docker image. Verify the workflow passes on push.