Capstone Projects

Capstones combine many modules into one realistic application.

Concept

Capstones combine many modules into one realistic application. Each has requirements, a suggested architecture and the modules it exercises. Build them in order; each is a portfolio piece.

Beginner Capstone — Student Management System Add, remove, update, search, sort students Save and load data (JSON) Validation and exception handling

A complete, verified reference solution follows in the Example section.

Intermediate Capstone — Inventory Management System Products, categories, stock movements, search and filtering, reports (low stock, value per category), persistence to a file and then to SQLite, LINQ everywhere. Architecture: domain classes → an IInventoryRepository with JSON and database implementations → a console or WPF UI. Modules: 13–17, 24, 27–28, 49–50, 53. (The core logic appears in the final assessment's intermediate problem.) Advanced Capstone — REST API + Database

An ASP.NET Core API for test benches and test runs: EF Core with SQLite/SQL Server and migrations, JWT authentication with roles and policies, structured logging, validation with ProblemDetails, OpenAPI documentation, unit tests for services, integration tests for endpoints and the database, a Dockerfile and a CI pipeline. Modules: 45–52, 59.

Expert Capstone — Engineering Diagnostic Platform CAN communication abstraction

ICanBus with simulator and vendor adapter Sessions, DIDs, DTCs, routines, NRC handling Benches, interfaces, ECUs, health

Channels, timeouts, cancellation, resilience Attribute-based test cases, runner, reports Test results, DTC history (EF Core) ASP.NET Core API + Blazor or a SPA

OpenID Connect / JWT, roles (Engineer, Viewer) JUnit XML, CSV, PDF Metrics, traces, health checks Configuration and logging Options, structured logs

flowchart LR
    CLIENT["Clients: dashboard, CLI, CI"] --> API["ASP.NET Core API: auth, validation, ProblemDetails, OpenAPI"]
    API --> SVC["Application services"]
    SVC --> EF["EF Core DbContext"]
    EF --> DB["SQL database"]
    API --> LOG["Logging + health checks"]
flowchart TB
    UI["Web dashboard"] --> GW["Platform API (auth, REST)"]
    GW --> TM["Test management service"]
    GW --> DM["Device management service"]
    TM --> BUS["Message broker (test jobs, results)"]
    DM --> BUS
    BUS --> AG["Bench agent (Windows/Linux PC at the bench)"]
    AG --> HW["CAN / DoIP / serial interfaces"]
    HW --> ECU["ECUs under test"]
    TM --> RDB["Results database"]
    AG --> OBS["OpenTelemetry: logs, metrics, traces"]

Why It Matters

Employers look for evidence that you can build complete systems: a working repository with tests, CI and documentation says more than any certificate.

Syntax

Start each capstone with dotnet new sln, projects per layer (dotnet new classlib, webapi, xunit), and dotnet sln add.

Example

64.1 Beginner capstone reference solution: Student Management System

using System.Text.Json;

// Student Management System: add, remove, update, search, sort, save, load, validation, exception handling
string file = "eh_students.json";
var store = new StudentStore();
store.Add(new Student(1, "Asha Rao", "Mechatronics", 8.7));
store.Add(new Student(2, "Ravi Kumar", "Electrical", 7.9));
store.Add(new Student(3, "Meera Iyer", "Mechatronics", 9.1));
Try(() => store.Add(new Student(4, "", "Civil", 7.0)));
Try(() => store.Add(new Student(2, "Duplicate", "Civil", 7.0)));
Try(() => store.Add(new Student(5, "Karan", "Civil", 11.5)));

store.Update(2, s => s with { Gpa = 8.2 });
store.Remove(1);
Console.WriteLine($"search 'mechatronics': {string.Join(", ", store.Search("mechatronics").Select(s => s.Name))}");
Console.WriteLine($"sorted by GPA desc: {string.Join(", ", store.SortedBy(s => s.Gpa, descending: true).Select(s => $"{s.Name} ({s.Gpa})"))}");

await store.SaveAsync(file);
var loaded = await StudentStore.LoadAsync(file);
Console.WriteLine($"saved and reloaded {loaded.Count} students; equal content: {loaded.All.SequenceEqual(store.All)}");
File.Delete(file);
Try(() => StudentStore.LoadAsync(file).GetAwaiter().GetResult());

static void Try(Action action
…

Expected Result

Every invalid operation was rejected with a clear message, the data survived a save/load round trip unchanged, and loading a missing file was reported as an error instead of crashing.

error: ArgumentException: Name is required
error: InvalidOperationException: student 2 already exists
error: ArgumentException: GPA 11.5 must be between 0 and 10
search 'mechatronics': Meera Iyer
sorted by GPA desc: Meera Iyer (9.1), Ravi Kumar (8.2)
saved and reloaded 2 students; equal content: True
error: FileNotFoundException: Could not find file 'eh_students.json'.

Common Mistakes

Starting with the UI instead of the domain and tests.

One giant Program.cs for an advanced capstone.

No persistence error handling (corrupt or missing files).

Skipping authentication/authorization "for now" in the API capstone.

No README explaining how to build, run and test.

Best Practices

Define requirements as tests/acceptance criteria first.

Commit early and often; set up CI on day one.

Keep hardware behind interfaces; ship a simulator mode.

Document architecture decisions (ADRs) and draw the architecture diagram.

Interview Relevance

High: "walk me through a project you built", "what would you do differently?", "how did you test it?", "how does it scale?" — capstones give you concrete answers.

Practice Questions

Add a GPA-based ranking report and CSV export to the student system.

Move the student store behind an IStudentRepository and add an EF Core implementation.

Implement the advanced capstone's POST /test-runs endpoint with validation and an integration test.

Write the bench agent of the expert capstone as a BackgroundService that pulls jobs from a channel.

Quick Quiz

Q1. (Multiple choice) Which layer should contain the rule "GPA must be between 0 and 10"? A) The UI B) The domain model (Student.Validate) C) The JSON file D) The database only

Answer: B — the UI and database can add checks, but the domain enforces it.

Q2. (True/False) The student system's Update validates the updated student before storing it.

Answer: True (the with expression creates a new record that is validated).

Q3. (Predict the output) Adding a student with an existing ID.

Answer: InvalidOperationException: student 2 already exists (verified).

Q4. (Find the bug) await JsonSerializer.SerializeAsync(File.Create(path), students);

Answer: The FileStream is never disposed, so the file stays locked and may not be flushed; use await using var stream = File.Create(path);.

Coding Challenge

Add a Statistics() method to the student store that returns the average GPA per branch, ordered by branch name, and print it.

var students = new List<Student>
{
    new(1, "Asha", "Mechatronics", 8.7), new(2, "Ravi", "Electrical", 8.2), new(3, "Meera", "Mechatronics", 9.1),
};
foreach (var (branch, average, count) in Statistics(students))
    Console.WriteLine($"{branch,-13} avg GPA {average:F2} ({count} students)");

static IEnumerable<(string Branch, double Average, int Count)> Statistics(IEnumerable<Student> students) =>
    students.GroupBy(s => s.Branch)
            .Select(g => (g.Key, g.Average(s => s.Gpa), g.Count()))
            .OrderBy(x => x.Key);

record Student(int Id, string Name, string Branch, double Gpa);