Skip to content
Skillpedia
APIs & servers (backend)280k · #50

dotnet-patterns

Enables your agent to apply patterns and best practices in C# and .NET. It's useful for writing or reviewing code, ensuring robust and maintainable applications.

What it does

This agent helps you write C# and .NET code following best practices. It suggests ways to organize your code to make it easier to understand, maintain, and faster.

When to use it

  • ✓When writing new C# code.
  • ✓When reviewing code written by someone else.
  • ✓When planning the structure of a new service.

Example of what to ask your AI

“How can I ensure my C# code is maintainable?”

Want more? Open the sections below.

How to use

The easiest way: copy the message below and paste it into Claude, ChatGPT, Cursor or any AI. It reads the skill and follows the instructions.

Skill link

https://github.com/affaan-m/ECC/blob/main/pi/core/skills/dotnet-patterns/SKILL.md

Ready-to-paste message

Use this skill to help me: https://github.com/affaan-m/ECC/blob/main/pi/core/skills/dotnet-patterns/SKILL.md Read the SKILL.md file at that link and follow its instructions for my task.
How it works

It analyzes your C# code and suggests improvements based on established patterns. It focuses on clarity, organization, and efficiency.

Installation

Easiest way: copy the skill link and paste it into Claude, ChatGPT or Cursor asking it to follow the instructions.

In the terminal (Claude Code, Codex, Cursor), in your project folder:

npx skills add affaan-m/ECC --skill dotnet-patterns

Or download just the file:

curl -L https://raw.githubusercontent.com/affaan-m/ECC/main/pi/core/skills/dotnet-patterns/SKILL.md -o SKILL.md
Technical content (original SKILL.md)

Original text by the author, straight from GitHub.

.NET Development Patterns

Idiomatic C# and .NET patterns for building robust, performant, and maintainable applications.

When to Activate

  • Writing new C# code
  • Reviewing C# code
  • Refactoring existing .NET applications
  • Designing service architectures with ASP.NET Core

Core Principles

1. Prefer Immutability

Use records and init-only properties for data models. Mutability should be an explicit, justified choice.

// Good: Immutable value object
public sealed record Money(decimal Amount, string Currency);

// Good: Immutable DTO with init setters
public sealed class CreateOrderRequest
{
    public required string CustomerId { get; init; }
    public required IReadOnlyList<OrderItem> Items { get; init; }
}

// Bad: Mutable model with public setters
public class Order
{
    public string CustomerId { get; set; }
    public List<OrderItem> Items { get; set; }
}

2. Explicit Over Implicit

Be clear about nullability, access modifiers, and intent.

// Good: Explicit access modifiers and nullability
public sealed class UserService
{
    private readonly IUserRepository _repository;
    private readonly ILogger<UserService> _logger;

    public UserService(IUserRepository repository, ILogger<UserService> logger)
    {
        _repository = repository ?? throw new ArgumentNullException(nameof(repository));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async Task<User?> FindByIdAsync(Guid id, CancellationToken cancellationToken)
    {
        return await _repository.FindByIdAsync(id, cancellationToken);
    }
}

3. Depend on Abstractions

Use interfaces for service boundaries. Register via DI container.

// Good: Interface-based dependency
public interface IOrderRepository
{
    Task<Order?> FindByIdAsync(Guid id, CancellationToken cancellationToken);
    Task<IReadOnlyList<Order>> FindByCustomerAsync(string customerId, CancellationToken cancellationToken);
    Task AddAsync(Order order, CancellationToken cancellationToken);
}

// Registration
builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>();

Async/Await Patterns

Proper Async Usage

// Good: Async all the way, with CancellationToken
public async Task<OrderSummary> GetOrderSummaryAsync(
    Guid orderId,
    CancellationToken cancellationToken)
{
    var order = await _repository.FindByIdAsync(orderId, cancellationToken)
        ?? throw new NotFoundException($"Order {orderId} not found");

    var customer = await _customerService.GetAsync(order.CustomerId, cancellationToken);

    return new OrderSummary(order, customer);
}

// Bad: Blocking on async
public OrderSummary GetOrderSummary(Guid orderId)
{
    var order = _repository.FindByIdAsync(orderId, CancellationToken.None).Result; // Deadlock risk
    return new OrderSummary(order);
}

Parallel Async Operations

// Good: Concurrent independent operations
public async Task<DashboardData> LoadDashboardAsync(CancellationToken cancellationToken)
{
    var ordersTask = _orderService.GetRecentAsync(cancellationToken);
    var metricsTask = _metricsService.GetCurrentAsync(cancellationToken);
    var alertsTask = _alertService.GetActiveAsync(cancellationToken);

    await Task.WhenAll(ordersTask, metricsTask, alertsTask);

    return new DashboardData(
        Orders: await ordersTask,
        Metrics: await metricsTask,
        Alerts: await alertsTask);
}

Options Pattern

Bind configuration sections to strongly-typed objects.

public sealed class SmtpOptions
{
    public const string SectionName = "Smtp";

    public required string Host { get; init; }
    public required int Port { get; init; }
    public required string Username { get; init; }
    public bool UseSsl { get; init; } = true;
}

// Registration
builder.Services.Configure<SmtpOptions>(
    builder.Configuration.GetSection(SmtpOptions.SectionName));

// Usage via injection
public class EmailService(IOptions<SmtpOptions> options)
{
    private readonly SmtpOptions _smtp = options.Value;
}

Result Pattern

Return explicit success/failure instead of throwing for expected failures.

public sealed record Result<T>
{
    public bool IsSuccess { get; }
    public T? Value { get; }
    public string? Error { get; }

    private Result(T value) { IsSuccess = true; Value = value; }
    private Result(string error) { IsSuccess = false; Error = error; }


…
FAQ

What are 'patterns' in programming?

Patterns are tested and proven solutions to common problems in software development. They help write more organized and efficient code.

What is 'dependency injection' (DI)?

It's a way of organizing code where 'dependencies' (other pieces of code a component needs to work) are provided from the outside, rather than the component creating them itself.

What does 'immutability' mean?

It means that data, once created, cannot be changed. This helps prevent errors and makes code more predictable.

Details

Original description by the author

Idiomatic C# and .NET patterns, conventions, dependency injection, async/await, and best practices for building robust, maintainable .NET applications. Use when writing or reviewing C# / .NET code — DI, async, or general conventions.

repo: affaan-m/ECC

Popularity

GitHub stars
280k
Ranking position
#50
License
MIT
Updated
10/15/2026

Is this skill useful?

0

Sign in to vote.

Comments

  • …

More skills from this repository

Similar skills