Claude
Skills
Sign in
Back

dotnet-framework

Included with Lifetime
$97 forever

# .NET Framework Skill - Quick Reference

General

What this skill does

# .NET Framework Skill - Quick Reference

**Framework**: .NET 8+ with ASP.NET Core
**For Agent**: backend-developer
**Purpose**: Fast lookup of common .NET patterns and conventions

---

## 1. ASP.NET Core Web APIs

### Controller-Based API

```csharp
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IMessageBus _bus;
    private readonly IQuerySession _session;

    public OrdersController(IMessageBus bus, IQuerySession session)
    {
        _bus = bus;
        _session = session;
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<OrderDto>> GetOrder(Guid id)
    {
        var order = await _session.LoadAsync<Order>(id);
        return order is not null
            ? Ok(OrderDto.FromEntity(order))
            : NotFound();
    }

    [HttpPost]
    public async Task<ActionResult<Guid>> CreateOrder(CreateOrderCommand command)
    {
        var orderId = await _bus.InvokeAsync<Guid>(command);
        return CreatedAtAction(nameof(GetOrder), new { id = orderId }, orderId);
    }

    [HttpPut("{id}")]
    public async Task<ActionResult> UpdateOrder(Guid id, UpdateOrderCommand command)
    {
        if (id != command.OrderId)
            return BadRequest("ID mismatch");

        await _bus.InvokeAsync(command);
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<ActionResult> DeleteOrder(Guid id)
    {
        await _bus.InvokeAsync(new DeleteOrderCommand(id));
        return NoContent();
    }
}
```

### Minimal API (.NET 8+)

```csharp
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

var orders = app.MapGroup("/api/orders")
    .WithTags("Orders")
    .WithOpenApi();

orders.MapGet("/{id}", async (Guid id, IQuerySession session) =>
{
    var order = await session.LoadAsync<Order>(id);
    return order is not null ? Results.Ok(order) : Results.NotFound();
})
.WithName("GetOrder")
.Produces<Order>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);

orders.MapPost("/", async (CreateOrderCommand cmd, IMessageBus bus) =>
{
    var orderId = await bus.InvokeAsync<Guid>(cmd);
    return Results.Created($"/api/orders/{orderId}", orderId);
})
.WithName("CreateOrder")
.Produces<Guid>(StatusCodes.Status201Created);

app.Run();
```

### Program.cs Setup

```csharp
var builder = WebApplication.CreateBuilder(args);

// Add services
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Marten configuration
builder.Services.AddMarten(opts =>
{
    opts.Connection(builder.Configuration.GetConnectionString("Postgres")!);
    opts.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate;

    // Document schema
    opts.Schema.For<Order>()
        .Index(x => x.CustomerId)
        .Index(x => x.Status);
});

// Wolverine message bus
builder.Host.UseWolverine();

var app = builder.Build();

// Middleware pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();
```

---

## 2. Wolverine Message Handling

### Command Handlers

```csharp
// Command
public record CreateOrderCommand(Guid CustomerId, List<OrderItem> Items);

// Handler (static method)
public static class CreateOrderHandler
{
    public static async Task<Guid> Handle(
        CreateOrderCommand command,
        IDocumentSession session,
        CancellationToken ct)
    {
        var order = new Order
        {
            Id = Guid.NewGuid(),
            CustomerId = command.CustomerId,
            Items = command.Items,
            Status = OrderStatus.Pending,
            CreatedAt = DateTimeOffset.UtcNow
        };

        session.Store(order);
        await session.SaveChangesAsync(ct);

        // Publish event
        await session.Events.Append(order.Id, new OrderCreated(order.Id, order.CustomerId));

        return order.Id;
    }
}
```

### Query Handlers

```csharp
// Query
public record GetOrderQuery(Guid OrderId);

// Handler
public static class GetOrderQueryHandler
{
    public static async Task<OrderDto?> Handle(
        GetOrderQuery query,
        IQuerySession session)
    {
        var order = await session.LoadAsync<Order>(query.OrderId);
        return order is not null ? OrderDto.FromEntity(order) : null;
    }
}

// Query with pagination
public record GetCustomerOrdersQuery(Guid CustomerId, int Page = 1, int PageSize = 20);

public static class GetCustomerOrdersHandler
{
    public static async Task<PagedResult<OrderDto>> Handle(
        GetCustomerOrdersQuery query,
        IQuerySession session)
    {
        var orders = await session.Query<Order>()
            .Where(o => o.CustomerId == query.CustomerId)
            .OrderByDescending(o => o.CreatedAt)
            .Skip((query.Page - 1) * query.PageSize)
            .Take(query.PageSize)
            .ToListAsync();

        var total = await session.Query<Order>()
            .CountAsync(o => o.CustomerId == query.CustomerId);

        return new PagedResult<OrderDto>(
            orders.Select(OrderDto.FromEntity),
            total,
            query.Page,
            query.PageSize
        );
    }
}
```

### Event Handlers

```csharp
// Event
public record OrderCreated(Guid OrderId, Guid CustomerId);
public record OrderShipped(Guid OrderId, string TrackingNumber);

// Event handler
public static class OrderCreatedHandler
{
    public static async Task Handle(
        OrderCreated evt,
        IDocumentSession session,
        ILogger<OrderCreatedHandler> logger)
    {
        logger.LogInformation("Order {OrderId} created for customer {CustomerId}",
            evt.OrderId, evt.CustomerId);

        // Trigger follow-up actions
        // Events are automatically cascaded if returned
    }
}
```

---

## 3. MartenDB Document Storage

### Basic Document Operations

```csharp
// Store document
public async Task<Order> CreateOrder(Order order)
{
    using var session = _store.LightweightSession();

    session.Store(order);
    await session.SaveChangesAsync();

    return order;
}

// Load document
public async Task<Order?> GetOrder(Guid id)
{
    using var session = _store.QuerySession();
    return await session.LoadAsync<Order>(id);
}

// Update document
public async Task UpdateOrder(Order order)
{
    using var session = _store.LightweightSession();

    session.Update(order);
    await session.SaveChangesAsync();
}

// Delete document
public async Task DeleteOrder(Guid id)
{
    using var session = _store.LightweightSession();

    session.Delete<Order>(id);
    await session.SaveChangesAsync();
}
```

### Querying with LINQ

```csharp
// Simple queries
var orders = await session.Query<Order>()
    .Where(o => o.CustomerId == customerId)
    .ToListAsync();

// Complex queries
var recentOrders = await session.Query<Order>()
    .Where(o => o.Status == OrderStatus.Pending)
    .Where(o => o.CreatedAt > DateTimeOffset.UtcNow.AddDays(-30))
    .OrderByDescending(o => o.CreatedAt)
    .Take(10)
    .ToListAsync();

// Aggregations
var totalAmount = await session.Query<Order>()
    .Where(o => o.CustomerId == customerId)
    .SumAsync(o => o.TotalAmount);

var orderCount = await session.Query<Order>()
    .CountAsync(o => o.Status == OrderStatus.Completed);
```

### Compiled Queries (Performance)

```csharp
public class OrdersByCustomer : ICompiledQuery<Order, IReadOnlyList<Order>>
{
    public Guid CustomerId { get; init; }

    public Expression<Func<IMartenQueryable<Order>, IReadOnlyList<Order>>> QueryIs()
    {
        return q => q.Where(x => x.CustomerId == CustomerId)
                     .OrderByDescending(x => x.CreatedAt)
                     .ToList();
    }
}

// Usage
var query = new OrdersByCustomer { CustomerId = customerId };
var orders = await session.QueryAsync(query);
```

---

## 4. Event Sourcing

### Event Stream Operations

```csharp
// Start new event stream
public async Tas

Related in General