The .NET Project — csproj, Program.cs and the SDK

Every .NET application begins as a project — a collection of source files described by a .csproj file. The .csproj uses the MSBuild XML format but the modern SDK-style format is dramatically simpler than the old full-framework format: typically 5–15 lines rather than 100+. Understanding the project file, the build output structure, and the CLI commands that drive the build lifecycle is foundational knowledge that applies to every project in this series — console applications, class libraries, ASP.NET Core Web APIs, and test projects.

The SDK-Style .csproj File

// ── A minimal ASP.NET Core Web API .csproj ────────────────────────────────
<!-- BlogApp.Api.csproj -->
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <RootNamespace>BlogApp.Api</RootNamespace>
    <AssemblyName>BlogApp.Api</AssemblyName>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
    <PackageReference Include="Serilog.AspNetCore"                     Version="8.0.0" />
    <PackageReference Include="FluentValidation.AspNetCore"             Version="11.3.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\BlogApp.Application\BlogApp.Application.csproj" />
    <ProjectReference Include="..\BlogApp.Infrastructure\BlogApp.Infrastructure.csproj" />
  </ItemGroup>

</Project>
Note: The Sdk attribute determines which implicit build targets and properties are activated. Microsoft.NET.Sdk is for console applications and class libraries. Microsoft.NET.Sdk.Web is for ASP.NET Core applications — it adds web-specific targets like static file copying and enables the Kestrel web server. Microsoft.NET.Sdk.Worker is for background services (Chapter 22). Choosing the wrong SDK causes subtle build failures — if your ASP.NET Core API project uses Microsoft.NET.Sdk, it will not include the web framework bootstrapping targets.
Tip: Set <TreatWarningsAsErrors>true</TreatWarningsAsErrors> in all production projects. Compiler warnings are early signals of potential bugs — unused variables, possible null dereferences, deprecated API usage. Treating them as errors prevents “I’ll fix this later” warnings from accumulating into technical debt. Configure specific warning codes to suppress (with <NoWarn>CS1591</NoWarn>) only for intentional cases like XML documentation warnings on internal types.
Warning: Never manually edit the obj or bin directories — these are generated build artefacts and are recreated on every build. Add them to .gitignore (the standard .NET .gitignore template handles this). If you experience inexplicable build errors after a merge, delete the obj directory (dotnet clean or manual deletion) and rebuild — stale generated files are a common cause of hard-to-diagnose build failures.

Build Output Structure

// Project directory layout after build:
// BlogApp.Api/
// ├── BlogApp.Api.csproj
// ├── Program.cs
// ├── Controllers/
// │   └── PostsController.cs
// ├── obj/                   ← intermediate build files (do not edit, gitignore)
// │   ├── Debug/
// │   └── Release/
// └── bin/                   ← compiled output (do not edit, gitignore)
//     ├── Debug/
//     │   └── net8.0/
//     │       ├── BlogApp.Api.dll      ← compiled assembly
//     │       ├── BlogApp.Api.exe      ← entry point (Windows) / launcher script (Linux)
//     │       └── BlogApp.Api.deps.json ← dependency manifest
//     └── Release/
//         └── net8.0/

Top-Level Program.cs (Minimal API Bootstrap)

// Program.cs — the application entry point (top-level statements, no Main method needed)
var builder = WebApplication.CreateBuilder(args);

// ── Register services ─────────────────────────────────────────────────────
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<AppDbContext>(opts =>
    opts.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

var app = builder.Build();

// ── Configure middleware pipeline ─────────────────────────────────────────
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Common Mistakes

Mistake 1 — Wrong SDK for the project type

❌ Wrong — using Microsoft.NET.Sdk for a web project (missing web targets):

✅ Correct — Microsoft.NET.Sdk.Web for ASP.NET Core; Microsoft.NET.Sdk for libraries and console apps.

Mistake 2 — Committing bin and obj to version control

❌ Wrong — binary build artefacts in source control bloat the repository and cause merge conflicts.

✅ Correct — ensure your .gitignore includes bin/ and obj/ at the root and in every project directory.

🧠 Test Yourself

What is the difference between PackageReference and ProjectReference in a .csproj file?