C# and .NET
Purpose
Build .NET applications that are null-safe by contract, correctly asynchronous end to end, and free of the ORM traps that quietly turn one query into a thousand.
When to Use
- Writing or reviewing C# on .NET 8 or later.
- Enabling nullable reference types on an existing project.
- Designing minimal APIs or ASP.NET Core services.
- Diagnosing async deadlocks or thread-pool starvation.
- Fixing EF Core N+1 queries and tracking overhead.
Capabilities
- Nullable reference types, records, pattern matching, required members.
- Async correctness:
ConfigureAwait, cancellation tokens, IAsyncEnumerable.
- Minimal APIs, endpoint filters, model validation, problem details.
- Dependency injection lifetimes and scope correctness.
- EF Core: projections, split queries, no-tracking reads, compiled queries.
Inputs
- Solution or project files and target framework.
- Whether the project is a library, web API, or worker service.
- Data-access layer and database engine.
Outputs
- Code compiling with
<Nullable>enable</Nullable> and <TreatWarningsAsErrors>true</TreatWarningsAsErrors>.
- Async paths that flow a
CancellationToken from request to database.
- EF Core queries with explicit projection and tracking behavior.
Workflow
- Enable the gates — Nullable reference types and warnings-as-errors, project-wide.
- Model — Records for immutable values;
required members instead of constructor sprawl.
- Thread cancellation — Every async method takes a
CancellationToken and passes it down.
- Shape the queries — Project to DTOs; never materialize entities you will not mutate.
- Gate — Build with warnings as errors, run analyzers, run the test suite.
Best Practices
- Never call
.Result or .Wait() on a Task. That is how deadlocks and starvation happen — async all the way down.
- Use
ConfigureAwait(false) in library code; it is unnecessary in ASP.NET Core application code.
- Register
DbContext as scoped. Injecting it into a singleton is a correctness bug, not a style issue.
- Read-only queries use
AsNoTracking(). Tracking every row you only intend to display wastes memory and time.
- Return
Results.Problem(...) / RFC 7807 payloads rather than bare status codes.
- Validate at the endpoint, not in the domain. The domain should be able to assume its inputs are valid.
Examples
Minimal API endpoint with cancellation and projection:
app.MapGet("/orders/{id:guid}", async (
Guid id,
AppDbContext db,
CancellationToken ct) =>
{
var order = await db.Orders
.AsNoTracking()
.Where(o => o.Id == id)
.Select(o => new OrderSummary(
o.Id,
o.Customer.Name,
o.Lines.Count,
o.Lines.Sum(l => l.Price * l.Quantity)))
.SingleOrDefaultAsync(ct);
return order is null
? Results.Problem(statusCode: 404, title: "Order not found")
: Results.Ok(order);
});
Notes
IAsyncEnumerable<T> streams results without buffering the full set — use it for large exports.
- EF Core's split-query mode avoids the cartesian explosion of multiple
Includes, at the cost of extra round trips. Measure both.
- Source generators (e.g.
System.Text.Json) remove reflection at startup and matter a great deal for AOT and cold-start latency.
1---2name: csharp-dotnet3description: Use when building on .NET 8+ with C# 12. Covers nullable reference types, records, async/await correctness, minimal APIs, dependency injection, and EF Core query performance.4---56# C# and .NET78## Purpose910Build .NET applications that are null-safe by contract, correctly asynchronous end to end, and free of the ORM traps that quietly turn one query into a thousand.1112## When to Use1314- Writing or reviewing C# on .NET 8 or later.15- Enabling nullable reference types on an existing project.16- Designing minimal APIs or ASP.NET Core services.17- Diagnosing async deadlocks or thread-pool starvation.18- Fixing EF Core N+1 queries and tracking overhead.1920## Capabilities2122- Nullable reference types, records, pattern matching, required members.23- Async correctness: `ConfigureAwait`, cancellation tokens, `IAsyncEnumerable`.24- Minimal APIs, endpoint filters, model validation, problem details.25- Dependency injection lifetimes and scope correctness.26- EF Core: projections, split queries, no-tracking reads, compiled queries.2728## Inputs2930- Solution or project files and target framework.31- Whether the project is a library, web API, or worker service.32- Data-access layer and database engine.3334## Outputs3536- Code compiling with `<Nullable>enable</Nullable>` and `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>`.37- Async paths that flow a `CancellationToken` from request to database.38- EF Core queries with explicit projection and tracking behavior.3940## Workflow41421. **Enable the gates** — Nullable reference types and warnings-as-errors, project-wide.432. **Model** — Records for immutable values; `required` members instead of constructor sprawl.443. **Thread cancellation** — Every async method takes a `CancellationToken` and passes it down.454. **Shape the queries** — Project to DTOs; never materialize entities you will not mutate.465. **Gate** — Build with warnings as errors, run analyzers, run the test suite.4748## Best Practices4950- Never call `.Result` or `.Wait()` on a Task. That is how deadlocks and starvation happen — async all the way down.51- Use `ConfigureAwait(false)` in library code; it is unnecessary in ASP.NET Core application code.52- Register `DbContext` as scoped. Injecting it into a singleton is a correctness bug, not a style issue.53- Read-only queries use `AsNoTracking()`. Tracking every row you only intend to display wastes memory and time.54- Return `Results.Problem(...)` / RFC 7807 payloads rather than bare status codes.55- Validate at the endpoint, not in the domain. The domain should be able to assume its inputs are valid.5657## Examples5859**Minimal API endpoint with cancellation and projection:**6061```csharp62app.MapGet("/orders/{id:guid}", async (63 Guid id,64 AppDbContext db,65 CancellationToken ct) =>66{67 var order = await db.Orders68 .AsNoTracking()69 .Where(o => o.Id == id)70 .Select(o => new OrderSummary(71 o.Id,72 o.Customer.Name,73 o.Lines.Count,74 o.Lines.Sum(l => l.Price * l.Quantity)))75 .SingleOrDefaultAsync(ct);7677 return order is null78 ? Results.Problem(statusCode: 404, title: "Order not found")79 : Results.Ok(order);80});81```8283## Notes8485- `IAsyncEnumerable<T>` streams results without buffering the full set — use it for large exports.86- EF Core's split-query mode avoids the cartesian explosion of multiple `Include`s, at the cost of extra round trips. Measure both.87- Source generators (e.g. `System.Text.Json`) remove reflection at startup and matter a great deal for AOT and cold-start latency.