mohamed TayelBuild Wassal v0 — a deliberately naive ASP.NET Core MVC monolith on .NET 8 + SQL Server — and tag it as the BEFORE state for the whole Fundamentals of Distributed Systems series.
Build the naive monolith we'll deliberately break in Lesson 1.
By the end of this hour, you'll have Wassal v0 running on your machine — a deliberately naive ASP.NET Core MVC monolith showing 5 restaurants from a SQL Server database, committed to git, and tagged as the BEFORE state for Lesson 1.
Here's the whole shape of what we're building today — one process, one database, no moving parts:
🎯 Today's goal: Wassal v0 running locally, committed, and tagged
lesson-01-before. Six sequential tasks, ~50 minutes.
Open PowerShell and confirm the three tools you'll need today are installed:
# .NET 8 SDK
dotnet --version # expect 8.x.x
# Local SQL Server (full instance, Windows Auth)
sqlcmd -S "(local)" -E -Q "SELECT @@VERSION" -h -1
# Git
git --version
💡 Missing something? Install via winget:
winget install Microsoft.DotNet.SDK.8·winget install Git.Git. SQL Server is assumed already installed locally (instance(local), Windows Auth).
✅ Done when: the sqlcmd call prints a version banner (e.g. "Microsoft SQL Server 2025 …"), and the other two commands return version numbers with no errors.
Navigate to the Wassal folder and initialize git:
cd D:\books\distributed-system\Wassal
git init
Download a clean .NET .gitignore from the official Microsoft repo:
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/dotnet/core/main/.gitignore" -OutFile ".gitignore"
Create README.md at the root:
# Wassal — A Distributed Food Delivery Lab
A hands-on learning project to apply concepts from the
Fundamentals of Distributed Systems course.
Built as a series of Before → After lessons starting from
a naive monolith and evolving into a production-grade
distributed system.
Commit:
git add .
git commit -m "chore: initial repo with docs and governance"
✅ Done when: git log shows one commit and git status is clean.
Create the solution and the first project:
dotnet new sln -n Wassal
dotnet new mvc -n Wassal.Monolith -o src/Wassal.Monolith --framework net8.0
dotnet sln add src/Wassal.Monolith/Wassal.Monolith.csproj
dotnet build
Expected layout after this step:
Wassal/
├── Wassal.sln
├── docs/ (already exists)
├── src/
│ └── Wassal.Monolith/
│ ├── Controllers/
│ ├── Models/
│ ├── Views/
│ ├── Program.cs
│ └── Wassal.Monolith.csproj
└── README.md
✅ Done when: dotnet build finishes with Build succeeded. 0 Warning(s) 0 Error(s).
You already have a full local SQL Server instance ((local), SQL Server 2025) running and accessible via Windows Authentication. No setup needed today; we just confirm it's reachable from a shell so EF Core migrations will work in the next step.
# 1. Confirm the connection works
sqlcmd -S "(local)" -E -Q "SELECT @@SERVERNAME, @@VERSION" -h -1
# 2. Create the WassalDb database up front (idempotent)
sqlcmd -S "(local)" -E -Q "IF DB_ID('WassalDb') IS NULL CREATE DATABASE WassalDb;"
💡 Why pre-create the DB? EF Core's
database updatewill create it automatically if your user has thedbcreatorrole, but pre-creating it avoids permission edge cases on locked-down Windows boxes.
✅ Done when: the first sqlcmd call returns the server name + version banner, and the second completes silently.
Add EF Core packages to the project:
cd src/Wassal.Monolith
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
cd ../..
If you don't have the EF CLI tool installed globally yet:
dotnet tool install --global dotnet-ef
Create the Restaurant model — src/Wassal.Monolith/Models/Restaurant.cs:
namespace Wassal.Monolith.Models;
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Cuisine { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public decimal Rating { get; set; }
}
Create the DbContext with seed data — src/Wassal.Monolith/Data/WassalDbContext.cs:
using Microsoft.EntityFrameworkCore;
using Wassal.Monolith.Models;
namespace Wassal.Monolith.Data;
public class WassalDbContext(DbContextOptions<WassalDbContext> opts)
: DbContext(opts)
{
public DbSet<Restaurant> Restaurants => Set<Restaurant>();
protected override void OnModelCreating(ModelBuilder b)
{
b.Entity<Restaurant>().HasData(
new Restaurant { Id = 1, Name = "Koshary El Tahrir", Cuisine = "Egyptian", City = "Cairo", Rating = 4.6m },
new Restaurant { Id = 2, Name = "Abou Tarek", Cuisine = "Egyptian", City = "Cairo", Rating = 4.8m },
new Restaurant { Id = 3, Name = "Burger Boutique", Cuisine = "American", City = "Cairo", Rating = 4.3m },
new Restaurant { Id = 4, Name = "Sushi Cairo", Cuisine = "Japanese", City = "Cairo", Rating = 4.1m },
new Restaurant { Id = 5, Name = "Pizza Hut", Cuisine = "Italian", City = "Giza", Rating = 3.9m }
);
}
}
Register the DbContext in Program.cs — add this before var app = builder.Build();:
using Microsoft.EntityFrameworkCore;
using Wassal.Monolith.Data;
// ... existing code ...
builder.Services.AddDbContext<WassalDbContext>(opts =>
opts.UseSqlServer(
"Server=(local);Database=WassalDb;" +
"Trusted_Connection=true;TrustServerCertificate=true"));
Create the database and run the migration:
dotnet ef migrations add InitialCreate --project src/Wassal.Monolith
dotnet ef database update --project src/Wassal.Monolith
💡 Verify the data: in SSMS, expand
WassalDb→Tables→dbo.Restaurants→ "Select Top 1000 Rows" — you should see all 5 seeded rows.
✅ Done when: the database WassalDb exists and the Restaurants table has 5 seeded rows.
Replace the Index action in src/Wassal.Monolith/Controllers/HomeController.cs:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Wassal.Monolith.Data;
public class HomeController : Controller
{
public async Task<IActionResult> Index([FromServices] WassalDbContext db)
{
var restaurants = await db.Restaurants
.OrderByDescending(r => r.Rating)
.ToListAsync();
return View(restaurants);
}
}
Replace the contents of src/Wassal.Monolith/Views/Home/Index.cshtml:
@model IEnumerable<Wassal.Monolith.Models.Restaurant>
@{ ViewData["Title"] = "Wassal — Restaurants"; }
<h1 class="display-5 mb-4">🍴 Restaurants in your city</h1>
<div class="row">
@foreach (var r in Model)
{
<div class="col-md-4 mb-3">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">@r.Name</h5>
<p class="text-muted mb-1">@r.Cuisine · @r.City</p>
<span class="badge bg-warning text-dark">⭐ @r.Rating</span>
</div>
</div>
</div>
}
</div>
Run the app from the repo root:
cd D:\books\distributed-system\Wassal
dotnet run --project src/Wassal.Monolith
Open the URL printed in the console (typically https://localhost:5001). You should see 5 restaurant cards sorted by rating.
Stop the app (Ctrl+C), then commit and tag the BEFORE state:
git add .
git commit -m "feat: Wassal v0 monolith — list restaurants from SQL Server"
git tag v0-monolith-baseline
git tag lesson-01-before
A tag is a permanent bookmark on a specific commit. Unlike a branch (which moves forward as you commit), a tag freezes a moment in time. Think of commits as pages of a book, branches as your hand moving through them, and tags as sticky notes on important pages.
Throughout this series, every lesson sets two tags that mark its boundaries:
lesson-XX-before — the starting state (the "pain" we'll feel)lesson-XX-after — the ending state (after applying the concept)This lets you later run git diff lesson-01-before lesson-01-after to see exactly what changed, or git checkout lesson-01-before to revisit any snapshot.
git tag # list every tag in this repo
git tag NAME # create a tag on the latest commit
git checkout TAGNAME # jump to that exact snapshot
git diff TAG1 TAG2 # see what changed between two tags
✅ Done when: the browser displays 5 restaurant cards, git log --oneline shows two commits, and git tag lists both v0-monolith-baseline and lesson-01-before.
| # | Task | Time | Done When |
|---|---|---|---|
| 1 | Verify Prerequisites | 5 min | 3 versions print without errors |
| 2 | Initialize the Repo | 10 min | Initial commit exists |
| 3 | Scaffold .NET Solution | 10 min |
dotnet build succeeds |
| 4 | Confirm Local SQL Server | 2 min | sqlcmd prints version + WassalDb created |
| 5 | EF Core + Seed | 15 min | 5 restaurants in DB |
| 6 | Render + Commit + Tag | 10 min | Browser shows cards, tags exist |
With Wassal v0 running and tagged as lesson-01-before, the next session installs k6, writes a load-test script, and watches the monolith collapse under 200 simulated users. That's the pain that gives meaning to every concept in the lessons that follow.
Part of the **Fundamentals of Distributed Systems* series — building Wassal, a distributed food-delivery lab, one concept at a time.*