ASP.NET Core

Six common ASP.NET Core Web API mistakes and the patterns to use instead

A developer who has maintained ASP.NET Core APIs for years lists six recurring problems: scattered try/catch blocks, unbounded list queries, ignored cancellation tokens, lost UTC kinds, late config failures and unprotected login endpoints. Each comes with a suggested pattern using .NET 10 and EF Core 10, noted to work on .NET 8 with small changes.

DEV Community: #aspnetcore Pankaj Singh
Published
Reading time
7 min read
agent run #10
agent run #10
Go to original dev.to

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • Handle errors in one IExceptionHandler that writes ProblemDetails; keep exception text out of 500 responses and add a traceId.
  • On list endpoints combine AsNoTracking, DTO projection, OrderBy and a hard page-size cap validated with FluentValidation.
  • Pass CancellationToken from the action down to EF Core calls such as ToListAsync(ct) and SaveChangesAsync(ct).
  • Store DateTime as UTC and restore DateTimeKind.Utc with a value converter; use TimeProvider for audit timestamps.
  • Bind options classes with ValidateDataAnnotations() and ValidateOnStart() so config mistakes fail at deploy time, and keep secrets out of git.
  • Apply the built-in rate limiter to login, register and refresh endpoints, and configure Forwarded Headers when behind a proxy.

The author, who has spent about four and a half years building and maintaining ASP.NET Core APIs on SQL Server and Azure, catalogs six problems that work in demos but fail in production. The fixes centre on one global IExceptionHandler that returns ProblemDetails, so controllers stay thin and internal error text never reaches clients. For lists, the advice is to combine no-tracking queries, DTO projection, a stable OrderBy and a hard page-size cap.

The remaining points cover passing CancellationToken down to EF Core so abandoned requests stop querying, storing UTC with a value converter because datetime2 loses its kind, and validating typed options at startup with ValidateOnStart and separate liveness and readiness health checks. The last item is built-in rate limiting on login and refresh endpoints, with a reminder to configure Forwarded Headers behind a proxy. The original post contains the full code samples.

Real-world use

  • A multi-controller enterprise API that needs consistent error responses and central logging.
  • A product catalogue endpoint serving hundreds of thousands of rows, where paging and no-tracking queries cut memory and latency.
  • A SaaS API with JWT login that must throttle password guessing and surface config errors during deploy.

Why it matters

Applying these patterns prevents many production issues before they happen: leaked stack traces, broken paging, wasted database work and config failures that only appear on the first request. Reviewing existing endpoints against this checklist is a practical starting point.

This summary was generated by the agent from the original post on DEV Community: #aspnetcore. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message