RSSAmplifier

Blog

Milan's .NET Weekly

Every Saturday morning I will send you 1 actionable tip on .NET that you can easily implement.

milanjovanovic.techRSS feed ↗207 posts

Latest posts

How Do You Build a Social Media Feed? (System Design)

The home feed looks like the easiest feature in a social app: fetch posts from the accounts you follow, sort, return a page.

Persisting a Rich Domain Model With EF Core

Every time I show a rich domain model, someone tells me it can't work with EF Core: "EF needs public setters and a public constructor, so the anemic model is…

Should You Split That Into Microservices? Ask These 5 Questions First

Nobody regrets microservices on day one. The regret shows up eighteen months later, when the team is drowning in distributed-systems problems they never needed…

The System Design Behind My New SaaS

I just shipped Katabench, and it's the most fun system I've ever built: it takes C# from strangers and runs it safely on servers I own.

How I Migrated My Website to Cloudflare and Saved $228

This website ran on Netlify for years, at $19 a month. Earlier this month I moved it to Cloudflare Pages: same repo, same GitHub Actions pipeline, zero…

How to Test Vertical Slice Architecture

The most common question I get about vertical slice architecture isn't about structure. It's "where do my tests go?" The layered-architecture testing habits…

Build Your Own VPN With Tailscale

Most of what runs on your servers was never meant to be public: databases, dashboards, admin panels, internal APIs.

Getting Started With NATS JetStream in .NET

NATS almost never comes up when .NET developers talk about message queues, and that's a shame.

The Modular Monolith Boundary I Couldn't Take Back

We built the system exactly the way a modular monolith is supposed to be built, and that's how I ended up with two modules I couldn't pull apart a year later.

Building Dapr Workflows in .NET With Aspire

Long-running business processes are hard to get right. Dapr Workflow lets you write them as plain C# code that survives crashes and restarts, and Aspire makes…

DRY Is the Most Misunderstood Rule in Programming

DRY was never about code that looks the same. It's about knowledge. Most of the tangled abstractions I've had to unwind started as a well-meaning attempt to…

Union Types Are Finally Coming to C#

For years we faked union types with marker interfaces, base classes, and the OneOf library.

How to Scale Long-Running API Requests

When a single API call takes minutes to finish, it punishes both your users and your server.

When Your Use Case Half-Succeeds: Designing for Partial Failure in .NET

A use case isn't a transaction. The moment it touches more than one system, you are dealing with partial failure.

API Versioning Should Be Your Last Resort

Most teams reach for v2 too early because they don't have a contract evolution strategy. Here's the API change management approach I prefer: evolve contracts…

What Invariants Are (and Why a Domain Model Is the Best Place to Enforce Them)

Most 'DDD-ish' code I review enforces business rules everywhere except where it should: in the model itself.

The Test Pyramid Is a Lie (and What I Do Instead)

The test pyramid made sense when integration tests meant a shared database server and a 20-minute build. It doesn't match how I build .NET systems in 2026.

Why I Switched to Primary Constructors for DI in C#

I resisted primary constructors for a while. They felt like a shortcut that would cost me later.

Implementing the Saga Pattern With Wolverine

Long-running business processes don't fit neatly into a single request. Wolverine's Saga support gives you a convention-based approach to orchestrating…

Implementing the Inbox Pattern for Reliable Message Consumption

The Outbox pattern guarantees reliable publishing. But what about the consumer side? The Inbox pattern ensures each incoming message is processed exactly once…

Getting Started With PgVector in .NET for Simple Vector Search

Vector search doesn't require a dedicated vector database. PostgreSQL with pgvector gives you similarity search right next to your relational data.

Scaling SignalR With a Redis Backplane

SignalR connections are server-local. Scale out to multiple instances and messages stop reaching the right clients.

Optimizing Bulk Database Updates in .NET: From Naive to Lightning-Fast

Seven approaches to bulk-updating rows in PostgreSQL from .NET using Dapper and EF Core, from naive per-row updates to binary COPY.

5 Architecture Tests You Should Add to Your .NET Projects

Learn about five essential architecture tests that can help ensure the quality and maintainability of your .NET projects.

How to Implement Two-Factor Authentication in ASP.NET Core

Passwords alone are not enough. Learn how to implement Two-Factor Authentication in .NET using TOTP, QR codes, and the Otp.NET library, with a secure setup…

Where Vertical Slices Fit Inside the Modular Monolith Architecture

Modular Monolith tells you how to split the system into modules. But it says nothing about how to organize code inside each module.

How to Extract Structured Data From Images Using Ollama in .NET

Vision models can do more than describe images. I used Ollama and Microsoft.Extensions.AI to extract structured receipt data into strongly typed C# objects…

Integrate Keycloak with ASP.NET Core Using OAuth 2.0

Learn how to integrate Keycloak with your .NET 10 API using Docker, Swagger UI with OAuth 2.0 Authorization Code flow, and JWT validation.

Containerize Your .NET Applications Without a Dockerfile

Learn how to containerize .NET applications without writing a single line of Dockerfile. The .NET SDK has built-in support for publishing directly to container…

A Practical Demo of Zero-Downtime Migrations Using Password Hashing

A practical demo of the zero-downtime migration pattern: run old + new password hash formats side-by-side, migrate users on login, and remove legacy safely.

Solving the Distributed Cache Invalidation Problem with Redis and HybridCache

Learn how to solve the distributed cache invalidation problem in .NET 9 by implementing a Redis Pub/Sub backplane to synchronize HybridCache instances across…

Solving Message Ordering from First Principles

Per-aggregate ordering is what we really want. But queues with competing consumers make it surprisingly easy to break.

The Urge to Build Something

Looking at my contribution graph now, I can see the whole journey mapped out in squares of green. The startup dreams. The pivot to teaching.

How to Build a High-Performance Cache Without External Libraries

Learn how to build a high-performance cache from scratch in .NET, moving from a simple ConcurrentDictionary to an optimized keyed-locking system.

Server-Sent Events in ASP.NET Core and .NET 10

ASP.NET Core 10 introduces native Server-Sent Events as a lightweight, HTTP-native alternative to SignalR for simple one-way real-time updates like dashboards…

The New .slnx Solution Format (migration guide)

See what changes in .slnx, how to convert your existing .sln, and what to watch out for in CI.

DbContext is Not Thread-Safe: Parallelizing EF Core Queries the Right Way

Learn how to safely parallelize EF Core queries to improve performance by using IDbContextFactory to create isolated contexts, avoiding the thread-safety…

Vertical Slice Architecture: Where Does the Shared Logic Live?

Deciding where shared logic lives is the most critical moment in Vertical Slice Architecture adoption, as choosing incorrectly reintroduces the coupling the…

The False Comfort of the "Happy Path": Decoupling Your Services

Coupling isn't just about code structure; it's about failure boundaries. Discover how to ensure your critical business logic survives when external…

Exploring C# File-based Apps in .NET 10

With .NET 10, Microsoft introduced file-based apps, which give you the ability to write C# code in a single .cs file and run it directly, without any project…

The Idempotent Consumer Pattern in .NET (And Why You Need It)

Distributed systems don't fail cleanly: they retry, duplicate, and occasionally fail. This article shows how to design resilient message handlers in .NET using…

What's New in EF Core 10: LeftJoin and RightJoin Operators in LINQ

.NET 10 finally adds proper LeftJoin and RightJoin methods to LINQ, replacing the complex GroupJoin + DefaultIfEmpty pattern with clean, readable code that…

The Interview Question That Changed How I Think About System Design

Discover how a simple interview question about report generation reveals the difference between optimizing code and designing scalable systems, and why the…

6 Steps for Setting Up a New .NET Project the Right Way

Learn how to properly set up a new .NET project with EditorConfig for code consistency, Directory.Build.props for centralized configuration, central package…

Building Fast Serverless APIs With Minimal APIs on AWS Lambda

Learn how to deploy ASP.NET Core Minimal APIs to AWS Lambda with just one library and a single line of code.

Using Stored Procedures and Functions With EF Core and PostgreSQL

Learn how to use PostgreSQL stored procedures and functions with EF Core to handle complex queries, atomic operations with locking, and database-specific…

Building Secure APIs with Role-Based Access Control in ASP.NET Core

Learn how to implement Role-Based Access Control (RBAC) in ASP.NET Core with custom authorization handlers, permission-based policies, and clean extension…

Distributed Locking in .NET: Coordinating Work Across Multiple Instances

Learn how to coordinate work across multiple application instances using distributed locking in .NET, preventing race conditions and ensuring data consistency…

Vertical Slice Architecture Is Easier Than You Think

Learn how Vertical Slice Architecture organizes .NET code by business features instead of technical layers, keeping related functionality together and making…

Building Semantic Search with Amazon S3 Vectors and Semantic Kernel

Learn how to add semantic search to your website using Amazon S3 Vectors - a new vector database service that's 90% cheaper than alternatives.