C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
72: Building a Minimal API
Wait, where are the Controllers?
If you've looked at ASP.NET Core tutorials from a few years ago, you're probably wondering why we aren't creating a Controllers folder and inheriting from ControllerBase. To be honest, for a lot of small-to-medium services, that boilerplate was just overkill. Minimal APIs let us strip all that away.
In a Minimal API, we map routes directly to delegates (usually lambdas) right in Program.cs. I've found this makes the codebase much easier to navigate when you're building microservices. Instead of jumping between three different files to see how one endpoint works, it's all right there.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// This is the "Minimal" way. No controller class needed.
app.MapGet("/status", () => new { Status = "Online", Timestamp = DateTime.UtcNow });
app.Run();
How do I actually handle dynamic data in a URL?
You aren't just building static pages; you need to fetch specific resources. For our "Digital Library" example, you'll want to get a book by its ID. You do this by adding a placeholder in the route string and adding a matching parameter to your lambda function.
C# is smart enough to handle the type conversion for you. If you define the parameter as an int, the framework will try to parse the URL segment automatically. If the user passes "abc" instead of a number, it'll just return a 400 Bad Request without you having to write a single line of validation code.
// Example: Fetching a book by ID
app.MapGet("/books/{id}", (int id) =>
{
// In a real app, you'd hit a database here
return Results.Ok($"Fetching details for book ID: {id}");
});
What's the best way to accept a JSON body?
When you're building a POST or PUT endpoint, you usually aren't passing IDs in the URL; you're sending a whole object. The beauty of Minimal APIs is that they handle the JSON deserialization behind the scenes. You just define a record or class that matches the expected JSON shape, and put it in the method signature.
I highly recommend using records for this. They are immutable and concise, which fits the "minimal" philosophy perfectly.
public record Book(string Title, string Author, int Year);
app.MapPost("/books", (Book book) =>
{
// The framework has already turned the JSON body into a 'book' object
return Results.Created($"/books/{book.Title}", book);
});
How do I get my services or database into these lambdas?
You might be thinking, "If there's no constructor, how do I use Dependency Injection?" The answer is simple: you just add the service as a parameter to the delegate. The framework looks at the requested type and resolves it from the DI container automatically.
I'll use a hypothetical IBookRepository here. Notice how the repository is passed in right alongside the route parameters. The order doesn't strictly matter, but it's a common pattern to put services first.
app.MapGet("/books", (IBookRepository repo) =>
{
var books = repo.GetAllBooks();
return Results.Ok(books);
});📋 Practical Task
Exercise: Build a Simple Inventory Tracker API
Your task is to create a Minimal API that manages a small inventory of electronics. Instead of a database, you can use a static List<Product> to keep things simple for this exercise.
Requirements:
- Define a
Productrecord withId(int),Name(string), andPrice(decimal). - Create a
GET /productsendpoint that returns the full list of products. - Create a
GET /products/{id}endpoint that returns a specific product or a404 Not Foundif the ID doesn't exist. - Create a
POST /productsendpoint that accepts aProductobject in the body and adds it to the list.
Tip: Use Results.NotFound() and Results.Ok() to ensure you are returning the correct HTTP status codes.
There are no comments for now.