An Attendance Platform in ASP.NET Core
Badge gates, WFH timers and shift allowances - the shape of a seven-project intranet attendance platform, the onion it almost is, and the roadmap for fourteen more parts.
348 articles filed under this topic.
Badge gates, WFH timers and shift allowances - the shape of a seven-project intranet attendance platform, the onion it almost is, and the roadmap for fourteen more parts.
A 6.23 MB JavaScript bundle loaded on every page, a manifest that minifies CSS but concatenates JS, and two copies of jQuery - the first of four frontend chapters the attendance series skipped.
Hard deletes destroy the audit trail; soft deletes clutter live tables forever. Introducing ArchiveKit, a .NET library that intercepts deletions and stores immutable archive snapshots with TTL policies and cascade archiving.
Unit tests mock what you assume, end-to-end tests tell you too late - consumer-driven contract testing closes the gap, and a small open-source .NET library called Pactify is the clearest way I know to learn how it works. Part 1 of a series.
The 22-part Convey series read the packages; it never once walked the sample system that ships with them. Opening the missing chapters with the trip an order takes through Orders, Pricing and Deliveries — and what the samples quietly teach that no package README does.
Rename a property, change a type, ship the release - and every payload you stored last year stops deserialising. Introducing VersionKit, a .NET library that declares schema history as attributes and migrates old data on read.
Controllers grow sideways and Minimal APIs grow into soup. FastEndpoints bets on a third shape - one class per endpoint - and this series reads its source to see how the bet is implemented. Part 1 of FastEndpoints in Depth.
Seventeen parts of reading FastEndpoints and the series never once mentioned mappers - the entity-translation layer half the endpoint base classes exist to serve. The Missing Chapters opens with the biggest gap: where mappers live, how they are found, and why they are secretly singletons. Part 1 of FastEndpoints — The Missing Chapters.
Inflow is a modular monolith whose modules agree on their boundaries and disagree about everything inside them - a four-project onion next to a single feature-sliced assembly. Part 1 of a series reading the money-moving half of the estate.
A teaching repo that implements one airline-charter domain three ways on purpose - CRUD, CRUD-plus-rich, and Clean Architecture - and persists it three ways to match. Part 1 of a source-reading series.
Every team's fifth microservice ships with the same four hundred lines of bootstrap code as the first four. Opening a deep-dive series on Convey, the open-source .NET toolkit that turned that boilerplate into thirty composable packages.
Database-per-tenant, schema-per-tenant, or packed into a shared database? Kicking off a series on building a multi-tenant platform where one EF Core codebase supports all three isolation strategies behind a single control plane.
DShop is one e-commerce shop stamped out as nine microservices over RabbitMQ - this series reads the real source to see how the topology holds together and where it drifts. Part 1 of Nine Services and a Message Bus.
A 2018 API gateway promises that routing, auth, validation and messaging need no code at all - this series reads the source that makes the promise true, and the places where it is not.
DevMentors' ModularMonolith sample packs three conference-system modules, a mini-framework and one deliberately broken contract into eighty-four C# files - opening a series that reads all of it, defects included.
A guided tour of FeedR, DevMentors' open-source .NET microservices sample for real-time data feeds - six services, Redis pub/sub, Apache Pulsar and a gRPC stream, and the two-tier eventing model that makes it worth reading. Part 1 of a source-level deep dive.
Split one database into five services and the transaction you deleted does not disappear - it goes feral. On sagas, compensation, process managers, and Chronicle, the small open-source .NET library this series reads line by line.
Dozens of Azure Functions and Logic Apps need each other's URLs and keys, and there is no Kubernetes, no sidecar, no mesh to hand them out. How a small .NET library turned one Key Vault and a naming convention into a working discovery layer - the consumer side of a registry made of secrets. Part 1 of a new series.
Reading a repository one project at a time hides everything that lives in the edges between them - and in this estate the edges are where the interesting failures are.
Convey sells a microservice in thirty lines, and Pacco builds ten of them - this series reads the whole estate to price what the framework compresses and what every consumer pays for by hand. Part 1 of The Convey Consumer Tax.
Five executables, zero queues - how an attendance platform coordinated a web app, three Azure Functions and a console job through one SQL database, and what that choice bought and cost. Part 1 of the series.
DShop.Common is the shared library nine microservices were built on - and the rough draft of a framework its authors later shipped as Convey.
Every modular monolith claims its modules are decoupled. Inflow proves it the only way that counts - by having no project reference between any two of them - and then has to build a whole mini-framework to make that survivable. Part 1 of a source-read through the shared layer.
Nobody in Pacco approves an order - a vehicle reservation does. A tour of DevMentors' parcel-delivery estate, the domain it models, and the fifteen-part series it earns.
Inflow ships an executable request collection - five .rest files, thirty-seven requests. On a fresh clone nine of them return a 2xx, and eight of those nine are in one file. This series reads the repository itself as the artefact.
Trill's Stories service is four projects with a dependency-free domain at the bottom. Its Users service is two projects with everything in one assembly - same author, same week, same estate, opposite answers to what a layer is.
The DevMentors Trill estate is a nine-service microservices sample spread over eleven sibling repositories with no README, no clone script and no bootstrap tooling - and the only artefact that names the whole system is a Visual Studio solution file.
What .NET Aspire actually does for a real multi-service system - the AppHost model, service defaults, the dashboard, and the road from F5 to deployment.
Wire four services into a .NET Aspire AppHost and run it once - traces, logs, health and environment variables for the whole system, before you have written a single line of observability code. Part 1 of a series on Aspire in production.
SaveChanges is already a transaction, until it isn't enough. A tour of explicit transactions, TransactionScope, execution strategies and the failure modes that only show up in production.
When a Chronicle saga rejects, the saga log is replayed backwards and every handled message gets its CompensateAsync called. Tracing both rejection paths through the source reveals a surprise - only one of them actually compensates - plus a ForEach that never awaits.
Seeker, initializer, processor, post-processor - Chronicle's whole runtime is four internal classes you can read in ten minutes. A source walk through the pipeline, including the gate that drops messages, the finally block that always persists, and the state that isn't as final as it looks.
services.AddChronicle() registers sagas you never mentioned, and one ProcessAsync call can run five of them in parallel. Inside Chronicle's Scrutor scan, the seeker's dedupe trick, and the ref-counted lock that serializes each saga id.
Correlation is the part of the saga pattern that fails silently. SagaId, SagaContext, the Empty-context trap that starts a new saga per message, and the one-method override that routes messages by their own content.
Split one database into five services and the transaction you deleted does not disappear - it goes feral. On sagas, compensation, process managers, and Chronicle, the small open-source .NET library this series reads line by line.
Chronicle's entire programming model is Saga<TData>, ISagaStartAction, and ISagaAction. Building a full order-fulfilment saga to learn what Complete() promises, what Reject() actually does, and why a saga can have more than one beginning.
After sixteen parts inside the source, the honest retrospective - what the library gets right, the sharp edges that will cut you (singletons, statics, magic), and the projects where I would leave it on the shelf. Part 17, the conclusion of FastEndpoints in Depth.
The cross-cutting drawer of FastEndpoints holds a rate limiter that documents its own limitations, idempotency built on output caching, server-sent events - and a full implementation of the x402 micro-payments protocol. Part 16 of FastEndpoints in Depth.
Everything FastEndpoints does with reflection - discovery, setters, factories - has a compile-time twin in its source generators, and following that migration is a case study in making a reflection-heavy library AOT-ready. Part 15 of FastEndpoints in Depth.
FastEndpoints ships a testing package where tests call endpoints by class name, apps boot once per fixture, and even command handlers can be faked - the route string never appears in a test. Part 14 of FastEndpoints in Depth.
FastEndpoints' job queues persist commands through a storage provider you supply and execute them with a semaphore design that idles without polling. The state machine in JobQueue.cs is worth the read on its own. Part 13 of FastEndpoints in Depth.
FastEndpoints.Messaging.Remote executes the same ICommand on another machine over gRPC, serialized with MessagePack instead of protobuf contracts - plus an event hub mode that turns a server into a lightweight broker. Reading it explains both the magic and the trade. Part 12 of FastEndpoints in Depth.
FastEndpoints ships in-process messaging that covers most MediatR use cases - events with three wait modes, commands with middleware pipelines, generic and streaming handlers. The dispatch code makes some sharp lifetime choices worth knowing. Part 11 of FastEndpoints in Depth.
FastEndpoints' Swagger support is a thousand-line translation layer that knows which DTO properties are route params, which FluentValidation rules are schema constraints, and which endpoint versions belong in which document. Part 10 of FastEndpoints in Depth.
FastEndpoints suffixes versions by default - /api/orders/v2 - and its release-group model versions endpoints, not APIs. Reading the route-building code explains the philosophy, and the AspVersioning bridge covers everyone it doesn't fit. Part 9 of FastEndpoints in Depth.
The FastEndpoints.Security package covers the token lifecycle end to end - creation with symmetric or RSA keys, an abstract refresh-token service that is secretly an endpoint, and a revocation middleware that makes you pay the lookup tax honestly. Part 8 of FastEndpoints in Depth.
Permissions(), Claims() and Scopes() in Configure() feel like magic until you read the mapping code - every endpoint gets its own named authorization policy built from closures at startup, and roles ride a plain AuthorizeAttribute. Part 7 of FastEndpoints in Depth.
FastEndpoints' processors are its cross-cutting hook - but their exact pipeline position, the shared state trick, and a captured exception that waits in a finally block are what make them genuinely useful. Part 6 of FastEndpoints in Depth.
FastEndpoints wires FluentValidation into the pipeline by request-DTO type, runs validators as singletons, and shares one failure list between binder, validator and handler. The lifetime rule is the part that bites. Part 5 of FastEndpoints in Depth.
FastEndpoints binds a single request DTO from JSON, form, route, query, claims, headers, cookies and permissions - in that order, with compiled setters cached per DTO type. Reading the binder explains every binding surprise I have ever hit. Part 4 of FastEndpoints in Depth.
AddFastEndpoints never asks you to register an endpoint. Reading the discovery code shows how a reflection scan over five interfaces becomes a validated endpoint catalogue - and which mistakes it turns into startup crashes on purpose. Part 2 of FastEndpoints in Depth.
Every FastEndpoints route is mapped as a Minimal API whose handler returns the same singleton IResult - and that one weird trick is the door into the whole per-request pipeline. Part 3 of FastEndpoints in Depth.
Controllers grow sideways and Minimal APIs grow into soup. FastEndpoints bets on a third shape - one class per endpoint - and this series reads its source to see how the bet is implemented. Part 1 of FastEndpoints in Depth.
Sync-over-async, a new HttpClient per call, out parameters everywhere - the discovery library needed a rewrite, and dozens of deployed consumers meant it could not break anyone. How the second generation shipped side by side with the first in the same NuGet package, what it fixed, and the one thing it deliberately kept. Part 7 of Service Discovery Without a Service Mesh.
The complete honest ledger for a Key Vault-backed service discovery layer after years in production - the debts I would pay tomorrow, the trade-offs I would sign again, and the concrete signals that it is time to graduate to App Configuration, APIM, Dapr or a mesh. Part 8, the finale of Service Discovery Without a Service Mesh.