.NET
Overview
.NET is Microsoft's open-source, cross-platform framework for building web APIs, cloud services, desktop applications, mobile apps, games, IoT, and AI/ML solutions. The modern .NET platform (6+) unifies what were formerly separate runtimes (.NET Framework, .NET Core, Mono) into a single SDK. C# is the primary language, with F# for functional programming. The ecosystem spans 400,000+ NuGet packages, first-party Azure integration, and tooling through Visual Studio, VS Code, and JetBrains Rider.
Knowledge Map
dotnet/
├── ai/ # ML.NET, ONNX, Azure AI, Microsoft.Extensions.AI, agents (A2A, MCP)
├── cli/ # Spectre.Console, CliWrap, command-line cheatsheet
├── cloud/ # Aspire, Azure Functions, Dapr, Orleans, service discovery
├── configuration/ # Extensions.Configuration, caching, feature flags, OpenFeature
├── data/ # EF Core, Dapper, Redis, Lucene.NET, FluentStorage
├── dependency-injection/ # Extensions.DI, Generic Host, Spring.NET
├── documentation/ # OpenAPI / Swagger
├── eventing/ # MediatR, MassTransit, NServiceBus, Rebus, Wolverine, Brighter, Akka.NET
├── functional/ # F#, Language.Ext, FParsec, Optional, pidgin
├── general/ # Humanizer, ImageSharp, NodaTime, Stateless, worker services, cheatsheet
├── localization/ # i18n, resource-based localization, MessageFormat
├── logging/ # Serilog, NLog, Extensions.Logging
├── mapping/ # AutoMapper, Mapperly
├── networking/ # gRPC, DotNetty, MimeKit, System.IO.Pipelines, Twilio
├── observability/ # OTLP logging, OpenTelemetry conventions
├── project-system/ # MSBuild/csproj, Roslyn analyzers, source generators, EditorConfig, Fody
├── reactive/ # Rx.NET, System.Threading.Channels, DynamicData, IAsyncEnumerable
├── resilience/ # Polly, Extensions.Resilience
├── security/ # ASP.NET Identity, cryptography, authorization (Topaz, Enforcer)
├── serialization/ # Protobuf-net, Bond, Hyperion, FluentSerializer
├── testing/ # Testcontainers, Moq, AutoFixture, Pact, Reqnroll, Playwright
├── ui/ # MAUI, Avalonia, Blazor, Uno Platform, Blazorise, MonoGame, Unity
├── validation/ # FluentValidation, Validot, Parse Don't Validate, CommunityToolkit.Guard
└── web/ # ASP.NET Core, SignalR, YARP, Ocelot, GraphQL, Refit, Orchard CMS
Choosing Guide
| Problem | Sub-Skill | Notes |
|---|---|---|
| Build a web API or microservice | web/aspnet-core | Minimal APIs for simple endpoints, controllers for complex APIs |
| Add real-time push to a web app | web/signalr | WebSocket abstraction with automatic fallback to SSE/long-polling |
| Reverse proxy or API gateway | web/yarp or web/ocelot | YARP for high-perf programmatic proxy, Ocelot for config-driven gateway |
| GraphQL API | web/graphql | Hot Chocolate server with filtering, sorting, subscriptions |
| Access a relational database | data/entity-framework-core | Full ORM with migrations, change tracking, LINQ queries |
| Lightweight SQL queries | data/dapper | Micro-ORM, raw SQL with object mapping, best for read-heavy paths |
| Distributed cache | data/redis or configuration/extensions-caching | Redis for shared cache, IMemoryCache/IDistributedCache for local/hybrid |
| Event-driven / CQRS architecture | eventing/mediatr | In-process mediator; combine with eventing/masstransit for cross-service |
| Message bus (RabbitMQ, Kafka, Azure SB) | eventing/masstransit | Abstraction over transports with sagas, retries, and outbox pattern |
| Build a .NET Aspire app | cloud/aspire | Orchestrate multi-project apps with built-in service discovery and telemetry |
| Serverless functions | cloud/azure-functions | Isolated worker model for Azure Functions with DI and middleware |
| Resilience (retries, circuit breakers) | resilience/polly | Configurable policies; use resilience/extensions-resilience for DI integration |
| Structured logging | logging/serilog | Sinks for Console, Seq, Elasticsearch, Application Insights |
| Object mapping | mapping/mapperly | Source-generator-based mapper (zero reflection, compile-time safe) |
| Input validation | validation/fluent-validations | Fluent rules with DI integration and ASP.NET Core auto-validation |
| Integration testing with real DBs | testing/testcontainers | Docker-based throwaway containers for Postgres, SQL Server, Redis |
| Mocking in unit tests | testing/moq | Proxy-based mocking with LINQ setup expressions |
| Contract testing | testing/pact | Consumer-driven contract tests for microservice boundaries |
| BDD / Gherkin | testing/reqnroll | SpecFlow successor — Given/When/Then with .NET 8+ support |
| Cross-platform desktop app | ui/avalonia | XAML-based UI for Windows, macOS, Linux, iOS, Android, WebAssembly |
| Mobile + desktop from one codebase | ui/maui | Microsoft's official cross-platform UI framework (.NET 8+) |
| Interactive web UI in C# | ui/blazor | Server-side or WebAssembly rendering with Razor components |
| Functional programming in C# | functional/language-ext | Immutable collections, Option/Either monads, pattern matching extensions |
| F# language guidance | functional/fsharp | Type providers, computation expressions, pipelines, domain modeling |
| AI/ML inference | ai/microsoft-extensions-ai | Unified abstraction for OpenAI, Azure AI, Ollama, and custom providers |
| Train ML models in .NET | ai/mlnet | AutoML, classification, regression, anomaly detection, recommendation |
| Build a CLI tool | cli/spectre-console | Rich terminal UI with tables, trees, progress bars, prompts |
| Source generators | project-system/generators-cheatsheet | Compile-time code generation with Roslyn incremental generators |
| Roslyn code analysis | project-system/roslyn-analyzers | Custom analyzers and code fixes for enforcing team conventions |
.NET Version Landscape
| Version | Release | Support | Key Features |
|---|---|---|---|
| .NET 6 | Nov 2021 | LTS (ended Nov 2024) | Minimal APIs, hot reload, DateOnly/TimeOnly, HTTP/3, AOT groundwork |
| .NET 7 | Nov 2022 | STS (ended May 2024) | Native AOT for console apps, rate limiting middleware, output caching |
| .NET 8 | Nov 2023 | LTS (until Nov 2026) | .NET Aspire, FrozenDictionary, keyed DI, native AOT for web, TimeProvider |
| .NET 9 | Nov 2024 | STS (until May 2026) | System.Threading.Lock, LINQ CountBy/AggregateBy, TypedResults improvements |
Choosing a Version
- Starting a new project? Use .NET 8 (LTS) for stability, or .NET 9 for latest features.
- In production with .NET 6? Plan migration to .NET 8 — .NET 6 support has ended.
- Need native AOT? .NET 8+ supports AOT for ASP.NET Core minimal APIs and gRPC.
- Using Aspire for orchestration? Requires .NET 8+.
C# Quick Reference
Modern C# Features (10-13)
// Global usings (C# 10) — reduce boilerplate across files
global using System.Text.Json;
global using Microsoft.Extensions.Logging;
// File-scoped namespaces (C# 10)
namespace MyApp.Services;
// Records with positional syntax — immutable data types
public record OrderPlaced(Guid OrderId, string CustomerId, decimal Total, DateTime PlacedAt);
// Primary constructors (C# 12) — DI without field ceremony
public class OrderService(IOrderRepository repo, ILogger<OrderService> logger)
{
public async Task<Order> GetAsync(Guid id)
{
logger.LogInformation("Fetching order {OrderId}", id);
return await repo.FindAsync(id) ?? throw new NotFoundException(id);
}
}
// Collection expressions (C# 12)
int[] numbers = [1, 2, 3, 4, 5];
List<string> names = ["Alice", "Bob", "Charlie"];
ReadOnlySpan<byte> header = [0x48, 0x54, 0x54, 0x50];
// Pattern matching with list patterns (C# 11)
string Describe(int[] values) => values switch
{
[] => "empty",
[var single] => $"one item: {single}",
[var first, .., var last] => $"from {first} to {last}",
};
// Raw string literals (C# 11) — no escaping needed
var json = """
{
"name": "Widget",
"price": 29.99,
"tags": ["electronics", "sale"]
}
""";
// Required members (C# 11)
public class Config
{
public required string ConnectionString { get; init; }
public required int MaxRetries { get; init; }
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(30);
}
// Switch expressions with property patterns
decimal CalculateDiscount(Order order) => order switch
{
{ Total: > 1000, Customer.IsPremium: true } => order.Total * 0.15m,
{ Total: > 500 } => order.Total * 0.10m,
{ Customer.IsPremium: true } => order.Total * 0.05m,
_ => 0m,
};
Key NuGet Package Categories
| Category | Go-To Packages | When to Use |
|---|---|---|
| Web Framework | ASP.NET Core (built-in) | REST APIs, Razor Pages, Blazor, gRPC |
| ORM | EF Core, Dapper | EF Core for full ORM, Dapper for raw SQL performance |
| Validation | FluentValidation, Validot | Fluent rule definitions, DI-friendly, auto-wire with ASP.NET |
| Mapping | Mapperly, AutoMapper | Mapperly for source-gen (zero reflection), AutoMapper for convention-based |
| Serialization | System.Text.Json, Protobuf-net | STJ for JSON (built-in), Protobuf for binary/gRPC |
| Logging | Serilog, NLog | Structured logging with sinks for Seq, Elastic, AppInsights |
| Testing | xUnit, Moq, AutoFixture, Testcontainers | xUnit as test framework, Moq for mocks, Testcontainers for integration |
| Resilience | Polly, Extensions.Resilience | Retry, circuit breaker, timeout, rate limiter policies |
| Messaging | MassTransit, MediatR, NServiceBus | MassTransit for bus abstraction, MediatR for in-process CQRS |
| DI | Extensions.DI (built-in) | Constructor injection, scoped/transient/singleton lifetimes |
| Caching | Extensions.Caching, StackExchange.Redis | IMemoryCache for local, IDistributedCache for Redis/SQL |
| HTTP Client | Refit, RestSharp | Refit for interface-defined clients, RestSharp for simpler REST calls |
| CLI | Spectre.Console, System.CommandLine | Rich terminal UIs, argument parsing, help generation |
| Cloud | .NET Aspire, Azure.Identity | Aspire for orchestration, Azure.Identity for managed identity auth |
Best Practices
-
Use the latest LTS release (.NET 8) for production workloads. LTS releases receive 3 years of security patches and bug fixes.
-
Enable nullable reference types (
<Nullable>enable</Nullable>) in every project. This catches null-reference bugs at compile time:<PropertyGroup> <TargetFramework>net8.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> -
Use
IOptions<T>pattern for configuration instead of reading values directly. This provides validation, reload support, and testability:public class SmtpOptions { public const string Section = "Smtp"; public required string Host { get; init; } public int Port { get; init; } = 587; public required string FromAddress { get; init; } } // In Program.cs builder.Services.AddOptions<SmtpOptions>() .BindConfiguration(SmtpOptions.Section) .ValidateDataAnnotations() .ValidateOnStart(); -
Prefer records for data transfer objects and events. Records provide value equality, immutability, and concise syntax. Use
record classfor heap-allocated (default) andrecord structfor stack-allocated small types. -
Use primary constructors for DI in services and controllers (C# 12). This eliminates boilerplate
private readonlyfields while keeping constructor injection. -
Avoid
async void— it swallows exceptions. Always returnTaskorValueTaskfrom async methods. The only exception is event handlers. -
Use
CancellationTokeneverywhere — pass it through all async call chains so requests can be cancelled cleanly when clients disconnect:app.MapGet("/orders/{id}", async (Guid id, IOrderRepository repo, CancellationToken ct) => await repo.FindAsync(id, ct) is { } order ? Results.Ok(order) : Results.NotFound()); -
Register services with the correct lifetime —
Singletonfor stateless/thread-safe services,Scopedfor per-request state (EF DbContext),Transientfor lightweight stateless operations. Never inject Scoped into Singleton. -
Use source generators over reflection where available (Mapperly, System.Text.Json source gen, Roslyn analyzers). Source generators run at compile time, eliminate reflection costs, and are compatible with Native AOT.
-
Structure solutions with clear project boundaries — separate API host, domain logic, infrastructure, and tests into distinct projects. Use
<ProjectReference>and enforce dependency direction (domain has no external references).