↑↓ to navigate Enter to open "…" all these words ANDOR to combine

Writing

Deep dives on enterprise .NET

A long-form series that turns the MMCA framework's architecture decisions into teachable patterns, every claim grounded in real source. Read in order it is a curriculum: the first few orient you, the middle ones cover the core patterns, data, and the API edge, and the last group is proof and getting started.

Every article is published here in full, numbered in reading order. Pieces that also ran on Medium link to that copy.

All articles

Orientation · No. 1

Open-sourced and graded against 34 categories

Why I open-sourced a production .NET framework and scored it against a 34-category architecture rubric, gaps and all.

Orientation · No. 3

The 34-category architecture rubric

A two-axis rubric for scoring architecture on maturity and implementation, so 'good architecture' stops being a vibe.

Core patterns · No. 4

The Result railway in C#

Model expected failures as Result values with a transport-agnostic error type, and keep exceptions for the genuinely exceptional.

Core patterns · No. 5

Kill the anemic domain model

Push behavior into rich aggregates with factory methods and invariants instead of bags of public setters.

Core patterns · No. 8

Compose validators, don't copy them

A validation kit that composes FluentValidation rules instead of copy-pasting them across features.

Data & persistence · No. 10

Database-per-service inside a monolith

Give each module its own database and outbox before you extract it, so extraction changes hosting, not data.

Data & persistence · No. 11

Polyglot persistence: one model, four engines

SQL Server, PostgreSQL, Cosmos, and SQLite behind a single entity model, with the engine chosen by attribute.

Data & persistence · No. 13

Optimistic concurrency: RowVersion round-trips

Carry the RowVersion from database to DTO and back, so a concurrent edit fails fast as a conflict instead of silently overwriting.

Data & persistence · No. 14

Self-ordering modules

Modules declare their dependencies and load in topological order, so registration is never hand-sequenced.

Data & persistence · No. 15

Event-schema versioning

Every integration event carries a schema version; breaking changes get a new event type and an upcaster, never a silent reshape.

Auth & the edge · No. 22

Live channels over one SignalR hub

Sub-second ephemeral events (polls, Q&A, live counts) fanned out over the existing notification hub, with nothing persisted.

Auth & the edge · No. 25

Browser session-cookie auth for Blazor SSR

HttpOnly session cookies and an SSR-time scheme so [Authorize] passes during prerender, with the API still the boundary.

Auth & the edge · No. 26

External OAuth login behind your own JWTs

Sign in with Google, GitHub or Apple without leaking provider tokens: external identity exchanged for your own JWTs at the boundary.

Auth & the edge · No. 27

Refresh tokens that rotate per device

A short-lived JWT plus a server-stored refresh session per device that rotates on every use, with reuse detection that makes a stolen token end its own session.

Proof & getting started · No. 35

The test pyramid

How the framework's tests stack up: fast unit and architecture tests at the base, E2E at the tip.

Proof & getting started · No. 38

i18n and theming on one preference pipeline

A culture choice and a theme choice ride the same cookie, profile column, and login reconciliation: one persistence path, two switches.

Proof & getting started · No. 41

Two real apps on one framework

A case study: a conference platform and an e-commerce store built on the same kernel.

Proof & getting started · No. 42

One Blazor UI, two hosts

The same Blazor components run in a browser and inside a MAUI hybrid app; small per-capability contracts reach native hardware without ever asking 'am I on mobile?'.

Data & persistence · No. 43

Managed file storage: uploads you don't have to trust

Attacker-controlled bytes become safe avatars: content sniffing, metadata stripping, re-encoding, and pluggable blob storage.

Auth & the edge · No. 44

HTTP API versioning, proven not just claimed

Header-based versioning introduced without breaking a single caller, plus a fitness contract that proves two live versions coexist.

Core patterns · No. 45

Feature flags in the CQRS pipeline

Gate commands and queries at the outermost decorator, so a handler never checks a flag and a disabled feature is rejected before any work runs.

Auth & the edge · No. 47

Security headers and CSP for Blazor

One middleware stamps hardened response headers on every host, with the Blazor CSP resolved through a pluggable provider.

Run & extract · No. 48

Observability by default

A shared OpenTelemetry baseline with CQRS duration metrics, correlation IDs, and outbox-poll span filtering, exported to Azure Monitor.

Core patterns · No. 49

Saga compensation and the reconciliation backstop

Undo as a first-class event handler: give back stock a committed transaction already took, with a periodic sweep as the saga-timeout backstop.

Run & extract · No. 50

The governed LLM boundary

A chat completion as a governed dependency: a pipeline of delegating clients that caps, guards, and meters every call to the model.

Core patterns · No. 51

Four ways to do work later

Channels, cron, the outbox, and durable internal commands: an ordinary CQRS command written inside your transaction and claimed by a leased worker.

Auth & the edge · No. 52

Finishing identity

A TOTP second factor, an email-confirmation gate, operator-editable permission grants and versioned Terms of Service acceptance, each arriving as an opt-in extension.