Tyler-R-Kendrick

dotnet

Use when working with C#, F#, .NET libraries, ASP.NET Core, Blazor, Entity Framework Core, and the broader .NET ecosystem. USE FOR: .NET language features, choosing libraries and frameworks, project structure, package selection, architecture decisions DO NOT USE FOR: specific library configuration details (use the sub-skills: web, data, testing, eventing, cloud, etc.)

Tyler-R-Kendrick 10 3 Updated 3mo ago

Resources

3
GitHub

Install

npx skillscat add tyler-r-kendrick/agent-skills/skills-dotnet

Install via the SkillsCat registry.

SKILL.md

.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

  1. Use the latest LTS release (.NET 8) for production workloads. LTS releases receive 3 years of security patches and bug fixes.

  2. 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>
  3. 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();
  4. Prefer records for data transfer objects and events. Records provide value equality, immutability, and concise syntax. Use record class for heap-allocated (default) and record struct for stack-allocated small types.

  5. Use primary constructors for DI in services and controllers (C# 12). This eliminates boilerplate private readonly fields while keeping constructor injection.

  6. Avoid async void — it swallows exceptions. Always return Task or ValueTask from async methods. The only exception is event handlers.

  7. Use CancellationToken everywhere — 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());
  8. Register services with the correct lifetimeSingleton for stateless/thread-safe services, Scoped for per-request state (EF DbContext), Transient for lightweight stateless operations. Never inject Scoped into Singleton.

  9. 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.

  10. 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).