Build real .NET backends. Not UI shells. Not Razor pages. Not MAUI. Build Kestrel-hosted services that stay clear under load, survive team growth, and remain easy to reason about in code review, LLD interviews, and production incidents.
Terminology Rule
Frame this skill as .NET 10 backend work.
- Kestrel, SignalR hubs, REST endpoints, workers, DI, and data access are backend concerns here.
- Do not describe this plugin's target using the web-stack brand name.
- Official Microsoft docs may still use that brand in article titles. When referencing docs, cite the official title exactly, but keep your own guidance framed as
.NET backend/Kestrel backend.
Scope
Focus on:
- Kestrel-hosted backend services
- REST endpoints, controllers, route groups, and SignalR hubs
- application/domain/infrastructure boundaries
- EF Core or pragmatic data-access decisions
- auth/authz boundaries, JWT posture, CORS, rate limiting, health checks, and graceful shutdown
- hosted services, concurrency, DI lifetimes, and messaging tradeoffs
- current backend guidance across
.NET 8,.NET 9, and.NET 10, with.NET 10as the default recommendation for new services
Do not drift into:
- MAUI, Blazor, Razor UI, WinUI, WPF, or desktop/mobile UI guidance
- front-end rendering or UX review
- CI/CD advice unless it directly changes backend architecture or operational behavior
Design Stance
Pick an architecture before adding layers:
- Default to a modular monolith. Split into distributed services only when bounded contexts, team topology, deployment independence, or failure isolation actually require it.
- Keep the host thin.
Program.cs, route groups, controllers, and hubs are composition surfaces, not homes for business logic. - Let application services orchestrate. Use cases, workflows, transactions, and coordination live here.
- Let the domain protect invariants. Entities and value objects should own rules that must remain true.
- Let infrastructure adapt. EF Core, Dapper, external APIs, message buses, and caches are details, not the center of the design.
- Prefer simplicity over ceremony. A boundary is only worth keeping if it prevents coupling, protects invariants, or improves testability and change safety.
- Treat vague coordination names as suspicious.
Coordinator,Orchestrator,Manager, andEngineoften hide kitchen-sink classes; make them prove they are focused.
Authority and Bias
Use a clear order of trust when making recommendations:
- Microsoft documentation settles framework behavior, lifetime rules, host semantics, and supported patterns.
- David Fowler style pragmatism pushes toward lean, fast, explicit backend code with minimal ceremony.
- Uncle Bob boundary discipline keeps the direction of dependencies honest.
- Martin Kleppmann skepticism reminds you that distributed systems are expensive, subtle, and easy to overbuild.
When these pull in different directions, choose the simplest design that preserves correctness, observability, and future change.
Modern .NET 10
Detect the real SDK and target framework from global.json, Directory.Build.props, *.csproj, or the solution. Recommend only features supported by the project. Use modern C# deliberately — not as syntax confetti. Prefer newer APIs when they clearly improve correctness, clarity, or performance. Do not force new syntax into a codebase that has an established style without a good reason.
Kestrel and Hosting
Kestrel is part of the backend architecture, not a deployment footnote. Review whether the service is intentionally internet-facing, whether proxy metadata is trusted safely, and whether protocol and request limits are explicit enough for the actual traffic.
Security and Operations
→ Security and operations reference
Review public-facing backend posture, not just code shape.
DO:
- keep authentication and authorization at clear boundaries
- keep browser-facing CORS explicit and narrow
- require an abuse/rate-limit story for public surfaces
- treat health checks and graceful shutdown as real backend behavior
DON'T:
- let services manually parse tokens or auth headers
- ship wildcard CORS on public backends
- ignore readiness, liveness, or shutdown behavior
Architecture and Boundaries
Keep dependency direction obvious:
- entrypoints call application services
- application services coordinate domain and infrastructure abstractions
- domain stays free of transport and persistence concerns
- infrastructure implements details behind boundaries
DO: keep endpoints, controllers, and hubs thin
DO: prefer a small number of obvious layers over many decorative ones
DO: separate contracts from entities
DON'T: let the host project become the application layer
DON'T: put business rules in controllers, route handlers, or SignalR hubs
DON'T: let Coordinator / Manager / Engine / Orchestrator types accumulate responsibilities unchecked
OOP and SOLID
Use OOP to model responsibilities and invariants, not to create inheritance tangles. High-level rules:
- classes need one reason to change
- interfaces should be small and boundary-driven
- composition beats inheritance by default
- abstractions should sit at seams, not everywhere
- files should stay small enough to review in one sitting
DO: split god services into focused services or domain types
DO: use value objects where they clarify invariants
DO: prefer explicit constructors and explicit dependencies
DON'T: create BaseService, BaseRepository, or giant utility classes
DON'T: create interfaces with one implementation and no real seam
DON'T: assume names like OrderCoordinator or WorkflowEngine make a wide class acceptable
Project Structure
Favor project layouts that make responsibilities obvious:
ApiorHostproject for Kestrel hostingApplicationproject for workflows and orchestrationDomainproject for core model and rulesInfrastructureproject for EF Core, clients, queues, cache, and adaptersContractsproject or folder for request/response/event models when shared boundaries justify it
Keep one major type per file when the type matters. Split files above 300 lines when they contain multiple responsibilities. Split urgently above 500 lines.
REST Endpoints and Contracts
Use minimal APIs or controllers intentionally. Either is fine if the boundary stays thin.
DO:
- validate at the boundary
- map domain/application outcomes to HTTP intentionally
- use typed request/response contracts
- keep route groups cohesive by feature
- keep status codes and
ProblemDetailsconsistent
DON'T:
- return EF entities directly from endpoints
- let handlers perform raw orchestration across five services
- mix validation, business rules, persistence, and transport mapping in one method
- treat versioning, pagination, or idempotency as afterthoughts
Real-Time Transports: SignalR vs Raw WebSockets vs SSE
Real-time push has three legitimate transports on Kestrel. Choose intentionally; do not default to SignalR for everything.
| Need | Best fit |
|---|---|
| One-way server → client streaming (notifications |