dotnet-best-practices

📁 akires47/agent-skills 📅 Jan 29, 2026
2
总安装量
2
周安装量
#64153
全站排名
安装命令
npx skills add https://github.com/akires47/agent-skills --skill dotnet-best-practices

Agent 安装分布

opencode 1
cursor 1
claude-code 1

Skill 文档

.NET Best Practices

Comprehensive development guide for modern .NET applications with C# 12+. Contains 100+ rules across 11 categories, prioritized by impact to guide code generation, refactoring, and reviews.

When to Apply

Reference these guidelines when:

  • Writing new C# code or refactoring existing code
  • Designing APIs, services, or domain models
  • Implementing data access layers or async operations
  • Reviewing code for performance, correctness, or maintainability
  • Setting up dependency injection, configuration, or logging
  • Writing tests (unit, integration, snapshot)
  • Building distributed systems or microservices

Rule Categories by Priority

Priority Category Impact Prefix Rules
1 Error Handling CRITICAL error- 8
2 Async Patterns CRITICAL async- 9
3 Type Design HIGH type- 10
4 Database Performance HIGH db- 12
5 API Design MEDIUM-HIGH api- 8
6 Dependency Injection MEDIUM di- 7
7 Architecture MEDIUM arch- 8
8 Serialization MEDIUM serial- 6
9 Performance LOW-MEDIUM perf- 12
10 Logging LOW-MEDIUM log- 6
11 Testing LOW test- 8

Total: 94 Rules

Quick Reference

1. Error Handling (CRITICAL)

  • error-result-pattern – Return Result for expected errors, not exceptions
  • error-validation-boundaries – Validate at handler entry points, fail fast
  • error-guard-clauses – Use guard clauses for null/range checks
  • error-exception-filters – Use catch when for selective exception handling
  • error-global-handlers – Implement middleware for unhandled exceptions
  • error-never-catch-all – Avoid catching all exceptions without rethrowing
  • error-custom-exceptions – Use built-in exceptions, avoid custom ones
  • error-exception-properties – Add context to exceptions via Data property

2. Async Patterns (CRITICAL)

  • async-cancellation-token – Always accept CancellationToken in async methods
  • async-all-the-way – Never block on async code with .Result or .Wait()
  • async-valuetask – Use ValueTask for hot paths with synchronous completions
  • async-iasyncenumerable – Use IAsyncEnumerable for streaming data
  • async-parallel-foreach – Use Parallel.ForEachAsync for bounded concurrency
  • async-channel – Use System.Threading.Channels for producer-consumer
  • async-semaphore – Use SemaphoreSlim for rate limiting
  • async-configureawait – Use ConfigureAwait(false) in library code
  • async-avoid-async-void – Never use async void except for event handlers

3. Type Design (HIGH)

  • type-records-for-dtos – Use records for immutable DTOs
  • type-readonly-record-struct – Use readonly record struct for value objects
  • type-seal-classes – Seal classes by default unless designed for inheritance
  • type-composition-over-inheritance – Prefer composition over inheritance
  • type-nullable-reference-types – Enable nullable reference types, handle nulls explicitly
  • type-pattern-matching – Use switch expressions and pattern matching
  • type-primary-constructors – Use primary constructors for simple classes
  • type-immutability-default – Design types to be immutable by default
  • type-explicit-conversions – Avoid implicit conversions for value objects
  • type-no-public-setters – Use init or constructor, not public setters

4. Database Performance (HIGH)

  • db-read-write-separation – Separate read models from write models
  • db-notracking-default – Configure NoTracking by default in EF Core
  • db-row-limits – Always apply row limits to queries
  • db-n-plus-one – Avoid N+1 queries with Include or batch fetching
  • db-cartesian-explosion – Use AsSplitQuery to prevent Cartesian products
  • db-compiled-queries – Use EF.CompileAsyncQuery for hot paths
  • db-connection-pooling – Use NpgsqlDataSource for connection pooling
  • db-optimistic-concurrency – Use RowVersion for concurrent updates
  • db-projections-over-entities – Use Select projections, not full entities
  • db-no-application-joins – Do joins in SQL, never in application code
  • db-bulk-operations – Use ExecuteUpdate/Delete for bulk modifications
  • db-no-generic-repositories – Use purpose-built stores, not generic repositories

5. API Design (MEDIUM-HIGH)

  • api-accept-abstractions – Accept IEnumerable/IReadOnlyCollection in parameters
  • api-return-specific-types – Return IReadOnlyList/IReadOnlyCollection from methods
  • api-readonly-collections – Return immutable collections from public APIs
  • api-method-overloads – Use overloads for common scenarios, not optionals
  • api-extension-methods – Use extension methods for fluent APIs
  • api-fluent-builders – Use builder pattern for complex object construction
  • api-async-suffix – Suffix async methods with Async
  • api-avoid-out-params – Return tuples or records instead of out parameters

6. Dependency Injection (MEDIUM)

  • di-extension-methods – Group service registrations in extension methods
  • di-lifetime-management – Understand Singleton, Scoped, Transient lifetimes
  • di-options-pattern – Use IOptions for configuration
  • di-validate-on-start – Call ValidateOnStart() for configuration validation
  • di-keyed-services – Use keyed services for multiple implementations
  • di-avoid-service-locator – Never inject IServiceProvider as service locator
  • di-no-scoped-in-singleton – Never inject Scoped services into Singleton

7. Architecture (MEDIUM)

  • arch-vertical-slice – Organize by feature (vertical slices), not layers
  • arch-feature-organization – One feature per file with all related code
  • arch-static-handlers – Use static handler methods in features
  • arch-module-boundaries – Use InternalsVisibleTo for module boundaries
  • arch-feature-flags – Implement runtime feature toggling
  • arch-background-services – Use IHostedService for background work
  • arch-minimal-apis – Prefer minimal APIs over controller-based APIs
  • arch-map-endpoints-per-feature – Each feature maps its own endpoints

8. Serialization (MEDIUM)

  • serial-system-text-json – Use System.Text.Json, not Newtonsoft.Json
  • serial-source-generators – Use JsonSerializerContext source generators
  • serial-protobuf – Use Protobuf for actor systems and event sourcing
  • serial-messagepack – Use MessagePack for high-performance scenarios
  • serial-wire-compatibility – Design for forward/backward compatibility
  • serial-no-type-names – Never embed type names in wire format

9. Performance (LOW-MEDIUM)

  • perf-span-and-memory – Use Span/Memory for buffer operations
  • perf-defer-enumeration – Don’t materialize IEnumerable until necessary
  • perf-frozen-collections – Use FrozenDictionary/FrozenSet for static data
  • perf-string-interpolation – Use string interpolation, not concatenation
  • perf-list-capacity – Initialize List with capacity when size is known
  • perf-dictionary-trygetvalue – Use TryGetValue instead of ContainsKey + indexer
  • perf-array-pool – Use ArrayPool for temporary large buffers
  • perf-object-pool – Use ObjectPool for expensive-to-create objects
  • perf-compiled-regex – Use GeneratedRegex source generator
  • perf-static-pure-functions – Prefer static methods for pure functions
  • perf-stackalloc – Use stackalloc for small temporary buffers
  • perf-avoid-closure-allocations – Cache delegates to avoid closure allocations

10. Logging (LOW-MEDIUM)

  • log-structured-logging – Use structured logging with named parameters
  • log-logger-message-define – Use LoggerMessage.Define for high-performance logging
  • log-correlation-ids – Implement request correlation via Activity.Current
  • log-activity-tracing – Use System.Diagnostics.Activity for distributed tracing
  • log-log-levels – Use appropriate log levels (Trace/Debug/Info/Warning/Error/Critical)
  • log-avoid-string-interpolation – Pass message template, not interpolated strings

11. Testing (LOW)

  • test-testcontainers – Use TestContainers for integration tests, not mocks
  • test-snapshot-testing – Use Verify for snapshot testing APIs and outputs
  • test-arrange-act-assert – Follow AAA pattern for test structure
  • test-fakes-vs-mocks – Prefer hand-written fakes over mocking libraries
  • test-data-builders – Use builder pattern for complex test data
  • test-integration-webappfactory – Use WebApplicationFactory for API integration tests
  • test-one-assertion-per-test – Focus each test on a single assertion
  • test-descriptive-names – Use descriptive test names that explain the scenario

How to Use

Read individual rule files for detailed explanations and code examples:

rules/error-result-pattern.md
rules/async-cancellation-token.md
rules/db-notracking-default.md

Each rule file contains:

  • Brief explanation of why it matters
  • ❌ Incorrect code example with explanation
  • ✅ Correct code example with explanation
  • Additional context and references

Full Compiled Document

For the complete guide with all rules expanded inline: AGENTS.md

This document is optimized for LLM context loading and contains all rules with full code examples.

Anti-Patterns Summary

Common mistakes to avoid:

Anti-Pattern Rule
Throwing exceptions for business logic error-result-pattern
Blocking on async code with .Result async-all-the-way
Mutable DTOs with public setters type-records-for-dtos
Queries without row limits db-row-limits
N+1 query problems db-n-plus-one
Returning List from APIs api-readonly-collections
Massive Program.cs with 200+ DI registrations di-extension-methods
Organizing by technical layers arch-vertical-slice
Using Newtonsoft.Json serial-system-text-json
String concatenation in loops perf-string-interpolation
Mocking databases in tests test-testcontainers

Resources