This episode covers modern .NET tooling: the dotnet CLI and MSBuild with SDK-style projects, build automation with GitHub Actions, source generators and Roslyn analyzer integration, and code formatting, linting, and reproducible builds.

A team doesn't just need correct code — they need a process that is repeatable, automated, and independent of any particular developer machine. This is where tooling and build automation come in.
The .NET CLI and MSBuild are the backbone of building, while CI pipelines like GitHub Actions automate the whole thing. Source generators and analyzers turn the compiler into a productivity tool that is active from the moment you write code.
Episode 18 covers SDK-style projects and MSBuild, CI with GitHub Actions, source generators and analyzers, and practices that produce reproducible builds.
SDK-style .csproj files are far shorter than legacy .NET Framework projects — all .cs files in the folder are included automatically:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project><Nullable>enable</Nullable> enables nullable reference types, and <ImplicitUsings>enable</ImplicitUsings> includes common usings automatically. Each property above is translated by MSBuild into compiler arguments and build targets.
A CI pipeline must run restore, build, and test on every change. An example GitHub Actions workflow:
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- run: dotnet restore
- run: dotnet build --no-restore -c Release
- run: dotnet test --no-build -c Release
- run: dotnet format --verify-no-changes --no-restoreThe workflow above runs automatically on a push to main or when a pull request is opened. actions/setup-dotnet@v4 sets up the SDK on the runner, and dotnet format --verify-no-changes ensures code style stays consistent. With runs-on: ubuntu-latest, the build runs in the same environment every time.
A source generator writes additional code during compilation, based on the existing code. This eliminates repetitive boilerplate. A simple generator example creates a partial method:
[AutoNotify]
public partial class Pengguna
{
public string Nama { get; set; }
}public partial class Pengguna
{
private void OnNamaChanged()
{
Console.WriteLine($"Nama berubah menjadi {Nama}");
}
}You don't write the second piece of code — it's generated by the compiler from the [AutoNotify] attribute. This is a great example of Roslyn's power: the compiler not only checks code, it can also write code.
Analyzers inspect your code for problematic patterns while you type, rather than waiting until runtime:
dotnet add package Microsoft.CodeAnalysis.NetAnalyzersThis analyzer warns about patterns such as allocation waste and async anti-patterns. With TreatWarningsAsErrors, analyzer warnings become build errors — forcing issues to be resolved rather than ignored.
To keep consistency across all projects, use Directory.Build.props, which applies to every project beneath it:
<Project>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
</Project>With this file, all projects inherit the same settings without repeating them in each .csproj. The <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> property makes builds reproducible — deterministic and independent of the build time or path.
Practices that guarantee quality at every step:
dotnet format for code style, verified in CI.dotnet build -warnaserror so warnings don't pile up.dotnet test to make sure nothing is broken.Key takeaways:
In the next episode 19 we bring code to production: deployment and cloud integration — Dockerizing .NET applications, deployment to Azure App Service, AWS, GCP, and Kubernetes, runtime configuration for production, and blue-green, canary, and rollback strategies.