Best practices · Stacks and tools
ASP.NET Core Best Practices
Opens with creditsA practical guide to ASP.NET Core best practices for developers building web APIs on .NET. It covers supported versions and project setup, dependency injection lifetimes and validated options, minimal APIs with built-in validation and OpenAPI, problem details errors, the async rules that prevent thread pool starvation, efficient EF Core queries, security and rate limiting, and testing and running in production.
What you will learn
8 chapters · about 17 min
1Versions and project setupWhich .NET version to run, and the compiler and package settings that catch bugs before they reach a pull request.3 practices · 2 min
2Dependency injection and configurationChoosing the right service lifetime, binding settings into validated options and keeping secrets out of appsettings.json.4 practices · 2 min
- Endpoints, validation and OpenAPIHow to shape endpoints with minimal APIs or controllers, validate input with the .NET 10 validation support and publish an accurate OpenAPI document.4 practices · 2 minOpens with credits
- Errors and problem detailsHow to return one consistent error format, handle exceptions in one place and keep exception details out of production responses.4 practices · 2 minOpens with credits
- Async code and performanceThe rules from the ASP.NET Core best practices article that prevent thread pool starvation, crashes and memory pressure under load.5 practices · 3 minOpens with credits
- Data access with EF CoreQuery patterns from the EF Core performance guidance that keep data access fast as tables grow.4 practices · 2 minOpens with credits
- Security and rate limitingAuthentication and authorization defaults, HTTPS, CORS and rate limits for public APIs.3 practices · 2 minOpens with credits
- Testing and running in productionIntegration tests with the real pipeline, structured logging, health checks and telemetry for the API once it is live.3 practices · 2 minOpens with credits
About this guide
ASP.NET Core best practices matter because the framework is fast by default and easy to slow down by accident. One .Result on a task in a hot path can starve the thread pool under load. A scoped DbContext captured by a singleton serves one request's data to the next. A lazy-loaded navigation property quietly turns one query into a hundred. None of these show up with three test users.
This guide starts with versions, which matter right now: .NET 8 and .NET 9 both reach end of support on November 10, 2026, and .NET 10 is the current LTS release. It then covers dependency injection lifetimes and the options pattern, building endpoints with minimal APIs, validation and OpenAPI, consistent problem details errors, async code and performance, data access with EF Core, security and rate limiting, and testing and running in production.
Everything here was checked against the Microsoft Learn documentation for ASP.NET Core 10 and .NET 10 (latest patch 10.0.12, September 2026), including the ASP.NET Core best practices article, which is the source of most performance advice in this guide.
Common questions
What is the latest version of .NET and ASP.NET Core?
As of October 2026, .NET 10 is the current LTS release, with patch 10.0.12 released on September 8, 2026, and ASP.NET Core 10 ships with it. .NET 8 and .NET 9 both reach end of support on November 10, 2026. Check the .NET support policy page for the current table.
Should I use minimal APIs or controllers in ASP.NET Core?
Both are supported. Minimal APIs need less code and, since .NET 10, validate data annotations with AddValidation(), which closes a gap with controllers. Controllers suit teams that rely on filters and conventions. Pick one style per service.
Is ASP.NET Core 8 still supported?
Until November 10, 2026. After that date .NET 8, and ASP.NET Core 8 with it, gets no more security patches. Plan the move to .NET 10, the current LTS release, now.
Why should I not use .Result in ASP.NET Core?
.Result and .Wait() block a thread pool thread until the task finishes. Under load this causes thread pool starvation, where requests queue and latency climbs even though the CPU is mostly idle. Use await through the whole call stack instead.
What lifetime should a DbContext have?
AddDbContext registers it as scoped, one per request, and that is the right default. Never inject it into a singleton. In background services, create a scope with IServiceScopeFactory and resolve the context from it.
How do I return consistent errors from an ASP.NET Core API?
Call AddProblemDetails(), then UseExceptionHandler() and UseStatusCodePages(). Errors then use the RFC 9457 problem details format. Map your own exceptions to status codes in an IExceptionHandler.
Sources (8)
Checked against these, last on 13 October 2026.
- .NET and .NET Core Support Policy, Microsoft .NETdotnet.microsoft.com/en-us/platform/support/policy/dotnet-core
- What's new in ASP.NET Core in .NET 10, Microsoft Learnlearn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-10.0
- ASP.NET Core Best Practices, Microsoft Learnlearn.microsoft.com/en-us/aspnet/core/fundamentals/best-practices
- Handle errors in ASP.NET Core APIs, Microsoft Learnlearn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling-api
- Service lifetimes (dependency injection), Microsoft Learnlearn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection/service-lifetimes
- Options pattern in .NET, Microsoft Learnlearn.microsoft.com/en-us/dotnet/core/extensions/options
- Rate limiting middleware in ASP.NET Core, Microsoft Learnlearn.microsoft.com/en-us/aspnet/core/performance/rate-limit
- Efficient Querying, EF Core docslearn.microsoft.com/en-us/ef/core/performance/efficient-querying
Related on Sefism
Picked from the other libraries by shared topics.
Roadmaps
See allCheat sheets
See allBest practices
See all- Spring Boot Best PracticesBuild Spring Boot 4 services that are easy to change and safe to run: injection, configuration, REST layer, JPA, virtual threads, Actuator, tests and shutdown.
- TypeScript Best PracticesModern TypeScript best practices for 2026: strict settings, TypeScript 7, modeling data with unions, safe narrowing, runtime validation, generics and typed linting.
- Secure Coding Best PracticesWrite code that resists attack: untrusted input, validation, parameterized queries, output encoding, safe parsing, uploads, SSRF and errors that fail closed.
Checklists
See all- Production Readiness ChecklistCheck a service before it takes real traffic: ownership, SLOs, capacity, timeouts and retries, alerts, rollout and rollback, backups, security and on-call.
- API Security ChecklistCheck your REST or GraphQL API against the OWASP API Security Top 10: authentication, object authorization, rate limits, input validation, SSRF, CORS and logging.
- Database Migration ChecklistCheck a schema or data migration before it ships: expand and contract, lock behaviour, online indexes, batched backfills, rehearsal on real data, backups, rollback, deploy order and monitoring.
Project structures
See all- Express with TypeScript project structureFor students who know a bit of JavaScript and want a backend that looks like the ones teams actually run. Express gives you almost no structure, so this layout supplies it: one folder per feature under src/modules, each split into routes, controller, service and repository, with Zod at the edge and Vitest plus Supertest for tests.
- NestJS project structureFor people who want a structured TypeScript backend with clear rules about where code goes. Every feature is a Nest module that owns its controller, service, DTOs, entities and tests, so the app grows by adding folders, not by stretching old ones. The tree follows one orders API from nest new to a codebase a whole team can run for years.
- FastAPI project structureA typed Python API for an orders app, built the way the FastAPI docs and the official full stack template lay it out: one
apppackage, a router per feature, Pydantic schemas at the edges, services in the middle and SQLAlchemy models with Alembic migrations underneath. For students who have finished the FastAPI tutorial and want to know where the second, tenth and fiftieth file go.
Career questions
See all- Should I use PostgreSQL or MongoDB for my project?For most student and startup projects, PostgreSQL is the safer default: relational data, joins, constraints and transactions fit most apps, and it handles JSON and vector search too. MongoDB is a good fit when your data is naturally document-shaped and varies a lot, or your team already knows it well. Model your data first, then choose.
- Should I use Firebase or Supabase for my app?Both let you ship an app fast with auth, a database, storage and hosting-style services. Supabase is built on PostgreSQL, so it suits relational data and SQL skills you will reuse anywhere. Firebase is a mature Google platform with a document database and strong mobile tooling. Choose by your data shape, your platform, and how much you want to learn transferable database skills.
- How do I learn system design as a student or junior developer?Start with the building blocks you already touch: HTTP, databases, indexes, caching and queues. Then study how real systems are built through engineering blogs, and practise by redesigning your own projects for more users. Classic design problems come last, once the fundamentals make sense.
Stuck on something specific?
Writing only gets you so far. If you want an answer to your situation rather than the general case, book a session and we will work through it together. Sessions are free for approved Sefism members, and a few slots open each week.
- 1:1 Mentorship
- Fresh Graduate Mentorship
- Career Guidance
Brand deals, promos and partnerships: tauseeffayyaz@gmail.com