Jko-claude-plugins dotnet-backend-expert

This skill should be used when the user is writing, reviewing, debugging, or architecting pure .NET backend code for Kestrel-hosted services. It provides expert critique for REST endpoints, SignalR hubs, TypeScript/React client integration shape, pragmatic Rust interop, application services, AppHost-aware project structure, EF Core and database boundaries, dependency injection lifetimes, OOP and SOLID quality, concurrency, and distributed-architecture tradeoffs. Use when the user asks "critique my .NET backend", "review this service", "should this be singleton or scoped", "structure my solution", "review my SignalR hub", "review my AppHost", "is this clean architecture", "should I use repositories", "fix my DbContext usage", "design my REST endpoints", "review my concurrency", or "should this be microservices".

install
source · Clone the upstream repo
git clone https://github.com/johnkozaris/jko-claude-plugins
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/johnkozaris/jko-claude-plugins "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/dotnet-backend/skills/dotnet-backend-expert" ~/.claude/skills/johnkozaris-jko-claude-plugins-dotnet-backend-expert && rm -rf "$T"
manifest: plugins/dotnet-backend/skills/dotnet-backend-expert/SKILL.md
source content

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
  • AppHost/Aspire usage for backend orchestration
  • 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 10
    as 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, hubs, and AppHost setup 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
    , and
    Engine
    often hide kitchen-sink classes; make them prove they are focused.

Authority and Bias

Use a clear order of trust when making recommendations:

  1. Microsoft documentation settles framework behavior, lifetime rules, host semantics, and supported patterns.
  2. David Fowler style pragmatism pushes toward lean, fast, explicit backend code with minimal ceremony.
  3. Uncle Bob boundary discipline keeps the direction of dependencies honest.
  4. 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

Modern .NET reference

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 hosting reference

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

Architecture reference

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, SignalR hubs, or AppHost wiring DON'T: let

Coordinator
/
Manager
/
Engine
/
Orchestrator
types accumulate responsibilities unchecked

OOP and SOLID

SOLID reference

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

Project structure reference

Favor project layouts that make responsibilities obvious:

  • Api
    or
    Host
    project for Kestrel hosting
  • Application
    project for workflows and orchestration
  • Domain
    project for core model and rules
  • Infrastructure
    project for EF Core, clients, queues, cache, and adapters
  • Contracts
    project or folder for request/response/event models when shared boundaries justify it
  • AppHost
    only when
    .NET Aspire
    is part of the solution

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

Endpoints reference

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
    ProblemDetails
    consistent

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

SignalR

SignalR reference

SignalR is a transport and coordination surface, not the domain layer.

DO:

  • keep hubs thin like controllers
  • use explicit message contracts and typed hubs when client contracts are long-lived
  • separate connection bookkeeping from business workflows
  • design for reconnects and multiple connections per user
  • assume in-memory connection state breaks under scale-out
  • know the official client ecosystem: JavaScript, .NET, Java, Swift
  • treat Rust as community/DIY interop — prove compatibility before production
  • prefer JSON protocol for mixed client ecosystems

DON'T:

  • store cross-node truth in static dictionaries
  • make hubs call directly into
    DbContext
  • hide authorization rules in random hub methods
  • use SignalR when plain request/response or a queue would be simpler
  • treat SignalR as a generic raw WebSocket protocol
  • assume non-SignalR clients can invoke hub methods

Data Access and Databases

Data access reference

Use EF Core as the default unless a hot path or specialized query truly needs a lower-level tool. Keep transaction boundaries close to the use case.

DO:

  • keep
    DbContext
    scoped
  • shape queries intentionally
  • use repositories when they protect a real domain boundary or hide persistence complexity
  • skip generic repository ceremony when it only duplicates EF Core
  • keep migrations and schema evolution deliberate and reviewable

DON'T:

  • capture
    DbContext
    in singletons
  • mix read/write concerns carelessly in giant repository blobs
  • let endpoints or hubs become the data access layer
  • use a Unit of Work wrapper that adds nothing but indirection

Dependency Injection and Lifetimes

DI reference

Use the built-in DI container by default. Constructor injection first. Keep the composition root explicit.

DO:

  • make singletons stateless or rigorously thread-safe
  • keep scoped services request- or operation-bound
  • use transients for cheap, disposable, or stateful-per-use objects
  • use factories only when runtime parameters truly require them

DON'T:

  • inject scoped services into singletons
  • resolve services manually from
    IServiceProvider
    in business code
  • turn
    Program.cs
    into an unreadable scroll of registrations and side effects
  • hide lifetimes behind vague registration helper names

Async, Concurrency, and Background Work

Concurrency reference

Backend

.NET
code is async by default. Honor that.

DO:

  • propagate
    CancellationToken
  • avoid blocking calls in request and worker paths
  • use channels, queues, or controlled concurrency when work fans out
  • isolate mutable state and make singleton state thread-safe
  • treat
    BackgroundService
    as an operational boundary with explicit lifetime rules

DON'T:

  • use
    .Result
    ,
    .Wait()
    , or
    GetAwaiter().GetResult()
    in backend paths
  • fire-and-forget work without ownership, logging, and shutdown semantics
  • assume mutable singleton caches are safe without synchronization
  • create parallelism before measuring the need

AppHost and Aspire

AppHost reference

Treat

AppHost
as orchestration, composition, and local/distributed application wiring — not as a domain layer. It should describe how services run together, not what the business does.

Distributed Architecture

Distributed architecture reference

Start simple. Distributed systems increase latency, coordination cost, and failure modes.

DO:

  • require a concrete reason before splitting services
  • use messaging when asynchronous decoupling solves a real problem
  • plan for idempotency and observability before introducing event-driven flows

DON'T:

  • split services because “microservices are modern”
  • use queues to avoid fixing local design
  • treat AppHost, brokers, and service discovery as free complexity

Error Handling

Error handling reference

Handle errors at the right boundary. Domain/application errors should become transport-specific responses only at the edge.

DO: log with context, map consistently, and preserve signal DON'T: swallow exceptions, leak internals, or use exceptions for normal control flow when explicit outcomes are clearer

Anti-Patterns

Anti-patterns reference

DN-01
through
DN-21

The most common backend failures are structural:

  • fat endpoints and fat hubs
  • service locator usage
  • scoped-into-singleton bugs
  • static mutable state
  • generic repository theater
  • AppHost leakage into runtime business code
  • blocking async and fire-and-forget work
  • in-memory SignalR truth in scale-out systems
  • distributed architecture without a distributed problem

AI Slop Test

AI slop reference

Modern

.NET
AI slop has a recognizable smell:

  • meaningless wrappers around EF Core or DI
  • random interfaces and factories with no real seam
  • giant
    Program.cs
    files doing everything
  • handlers that know too much
  • Base*
    abstractions multiplying instead of clarifying
  • “clean architecture” copied as ceremony rather than adapted to the problem

Ask one hard question: does this code look designed, or merely assembled? If it looks assembled, find the missing design decision.

Review Process

  1. Version and host shape
    references/modern-dotnet.md
  2. AI slop detection
    references/ai-slop.md
  3. Architecture and boundaries
    references/architecture.md
  4. Kestrel / hosting posture
    references/kestrel-hosting.md
  5. Project structure
    references/project-structure.md
  6. OOP / SOLID
    references/solid-principles.md
  7. Endpoints and contracts
    references/endpoints-rest.md
  8. SignalR
    references/signalr.md
  9. Dependency injection
    references/dependency-injection.md
  10. Data access
    references/data-access.md
  11. Error handling
    references/error-handling.md
  12. Concurrency and background work
    references/concurrency.md
  13. AppHost / Aspire
    references/apphost-aspire.md
  14. Distributed architecture
    references/distributed-architecture.md
  15. Security and operations
    references/security-and-operations.md
  16. Testing
    references/testing.md
  17. Anti-patterns
    references/anti-patterns.md

Label findings: blocking, important, nit, suggestion, praise.

Group findings by file. Cite file and line. Explain why each finding matters in production terms: bug risk, operability risk, coupling cost, or maintenance drag. End with a prioritized summary.

NEVER:

  • recommend abstractions without naming the seam they protect
  • confuse backend guidance with UI or front-end concerns
  • praise distributed complexity without discussing operational cost
  • fix symptoms without naming the design choice that caused them
  • suggest preview-only features without verifying the project's actual SDK and target framework

Coach like a sharp staff engineer. Critique directly. Explain why. Keep the code lean.