Page 3 of 7
Custom JSON Converters in System.Text.Json
System.Text.Json handles most serialization scenarios out of the box, but every sufficiently complex application eventually hits a case where the default behaviour just isn't right. Maybe you've got a...
TimeProvider in .NET
If you've ever written code that calls DateTime.UtcNow or DateTimeOffset.Now directly, you've probably felt the pain in tests. The current time is hard to control, which means any test that depends on...
The Result Pattern in C#
Throwing exceptions for expected failure cases has always felt a bit off. An exception should be exceptional — something you genuinely didn't anticipate. But in most applications, "user not found" or ...
Built-in OpenAPI in ASP.NET Core
For years, if you wanted OpenAPI support in an ASP.NET Core app, you reached for Swashbuckle. It's been the de-facto standard — add the NuGet package, sprinkle some XML doc comments, call AddSwaggerGe...
Native AOT in .NET 10
For most of .NET's history, your code ran with a JIT compiler warming things up at startup. That's fine for long-running services, but there are scenarios where you want a self-contained binary that s...
Expression Trees in C#
Lambda expressions in C# do double duty. Most of the time they're just delegates — compiled functions you call directly. But when assigned to Expression<TDelegate>, they become data: a tree of objects...
Cancellation Tokens in C#
Async code doesn't run forever in a vacuum. Users cancel requests, clients disconnect, timeouts fire, and applications shut down. Without a way to signal that a running operation should stop, you end ...
Frozen Collections in .NET
Most collections in .NET are designed for mutation. You add items, remove them, update values. But there's a whole class of data that never changes after it's been set up — configuration lookups, coun...
Concurrent Collections in .NET
Threading bugs are some of the nastiest bugs to track down. They appear intermittently, vanish under the debugger, and tend to manifest in production at the worst possible time. One common source of t...
TCR for Agentic Loops: Guiding LLM Agents
The TCR post on this blog showed how test && commit || revert forces human developers to take smaller steps by making the machine enforce discipline. But what happens when the "developer" is an autono...
TCR: Test && Commit || Revert in C#
If you've read the TDD post on this blog, you know the red-green-refactor loop: write a failing test, make it pass, clean up. TCR takes that idea and cranks it up to eleven. Instead of a discipline yo...
Dapper: Lightweight SQL in .NET
Entity Framework Core is great for a lot of scenarios, but sometimes you just want to write SQL and get results back without the overhead. That's where Dapper comes in. It's a micro-ORM — essentially ...
EF Core Performance Tips in .NET
Entity Framework Core is fantastic for getting database access up and running quickly. But if you're not careful, it can quietly generate some impressively inefficient SQL. The good news: most EF Core...
Vertical Slice Architecture
If you've spent time working in layered architecture — controllers, services, repositories, all the way down — you've probably felt the friction. Adding a feature means touching four or five layers, t...
Event Sourcing in .NET
Yesterday we looked at CQRS, which separates reads from writes. Today's topic pairs naturally with it: event sourcing. Instead of storing the current state of your entities, you store the sequence of ...