ASP.NET Core Web API: Complete Developer Guide
A comprehensive reference to HTTP, REST, controllers, routing, Minimal APIs, validation, dependency injection, EF Core, security, testing, performance, and deployment.
These notes bring the complete ASP.NET Core Web API subject together in one reference. They complement the 30-day Web API series: the daily articles teach individual concepts, while this guide connects the concepts into a complete developer learning path.
| Scope | Details |
|---|---|
| Platform | ASP.NET Core 10 / .NET 10; target framework net10.0 |
| Purpose | Complete reference, not a day-by-day article series |
| Use | Study concepts, build examples, test behavior and apply production practices |
Learning Map
- HTTP fundamentals and REST
- ASP.NET Core architecture and project setup
- Program.cs, dependency injection and middleware
- Controllers, actions, Minimal APIs and routing
- HTTP methods, status codes, headers and content negotiation
- Model binding, validation, DTOs and JSON
- EF Core, CRUD, LINQ, relationships and migrations
- Transactions, concurrency and query performance
- Error handling, Problem Details and logging
- Authentication, JWT, OAuth 2.0 and OpenID Connect
- Authorization, roles, claims and policies
- CORS, CSRF, HTTPS and API security
- Pagination, filtering, sorting and file handling
- Caching, rate limiting, resilience and API versioning
- OpenAPI, health checks, observability and testing
- Configuration, deployment, containers and production readiness
1. What Is a Web API?
A Web API exposes application functionality and data over HTTP so web, mobile, desktop and service clients can communicate with an application.
- Client sends an HTTP request.
- API validates input and applies business rules.
- Services coordinate data access and external dependencies.
- API returns a status code, headers and optionally a representation such as JSON.
Client → HTTP Request → ASP.NET Core Web API → Services / Data Access → Database
Client ← HTTP Response ← ASP.NET Core Web API ← Result / DTO
A Web API is not a database, user interface or programming language. It is an HTTP-based application boundary.
2. HTTP Fundamentals
| Term | Meaning |
|---|---|
| HTTP | Application protocol for request/response communication. |
| HTTPS | HTTP protected by TLS encryption. |
| Request | Method, URL, headers and optional body. |
| Response | Status code, headers and optional body. |
| Content-Type | Describes the message body media type. |
| Accept | Lists response media types accepted by the client. |
| Method | Purpose | Semantics |
|---|---|---|
| GET | Retrieve a resource | Safe, idempotent |
| POST | Create or process | Not generally idempotent |
| PUT | Replace resource representation | Idempotent |
| PATCH | Partially modify resource | Not inherently idempotent |
| DELETE | Remove resource | Idempotent |
| HEAD | GET-like headers without body | Safe, idempotent |
| OPTIONS | Describe communication options | Safe, idempotent |
Safe means intended not to change server state. Idempotent means repeating the same request has the same intended effect as performing it once.
3. REST Resource Design
- Model endpoints around resources such as products, customers and orders.
- Use nouns in paths; HTTP methods express the operation.
- Use route parameters to identify resources and query parameters for filtering, sorting and pagination.
- Keep response contracts consistent and avoid exposing database entities directly.
GET /api/products
GET /api/products/42
POST /api/products
PUT /api/products/42
PATCH /api/products/42
DELETE /api/products/42
REST is an architectural style, not a requirement to expose database tables directly.
4. .NET 10 and ASP.NET Core Architecture
- .NET is the platform; ASP.NET Core is its web framework.
- The SDK provides templates, CLI tools, compiler and build tools.
- The runtime executes applications; shared frameworks provide libraries.
- Kestrel is the cross-platform web server commonly used by ASP.NET Core.
- The host manages startup, configuration, logging and dependency injection.
- Middleware processes HTTP requests and responses.
- Endpoint routing selects the endpoint that handles a request.
| Component | Purpose |
|---|---|
| SDK | Build tools, CLI, templates and compiler |
| Runtime | Executes .NET applications |
| Kestrel | ASP.NET Core web server |
| Middleware | Sequential request/response processing |
| Endpoint | Selected request handler |
| DI container | Creates and supplies registered dependencies |
5. Create a .NET 10 Web API
dotnet --info
dotnet new webapi -n StoreApi
cd StoreApi
dotnet run
Confirm the project targets net10.0. Depending on template options, a project may use Minimal APIs or controller-based endpoints.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
6. Project Structure
StoreApi/
├── Controllers/ # HTTP controllers
├── Models/ # Domain/persistence models
├── DTOs/ # Request and response contracts
├── Services/ # Business/application logic
├── Data/ # DbContext and data configuration
├── Middleware/ # Custom middleware
├── Filters/ # MVC filters
├── appsettings.json # Configuration
├── Program.cs # Service and pipeline setup
└── StoreApi.csproj
This is a convention, not a required structure. Larger applications may use feature folders or separate domain, application, infrastructure and API projects.
7. Program.cs, Services and Middleware
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Register services through builder.Services before Build(). Configure middleware after Build(). When authentication is configured, UseAuthentication() must run before UseAuthorization(). Add OpenAPI/UI components only when configured in the project.
8. Controllers and Actions
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult GetAll() => Ok(new[] { "Keyboard", "Mouse" });
[HttpGet("{id:int}")]
public IActionResult GetById(int id) =>
id == 1 ? Ok(new { Id = id, Name = "Keyboard" }) : NotFound();
}
- ControllerBase is designed for APIs and does not provide Razor view support.
- Controller is used by MVC applications that need views.
- [ApiController] enables API conventions such as automatic 400 responses for model validation errors and binding-source inference.
- Actions commonly return IActionResult, ActionResult<T> or asynchronous equivalents.
9. Minimal APIs vs Controller-Based APIs
| Minimal APIs | Controller APIs |
|---|---|
| Map route handlers directly. | Group actions into controller classes. |
| Concise for small services and focused endpoints. | Useful for larger APIs and MVC conventions. |
| Use endpoint filters. | Use MVC filters and action conventions. |
| Support DI, validation and OpenAPI integrations. | Support DI, validation and OpenAPI integrations. |
var group = app.MapGroup("/api/products");
group.MapGet("/", () => Results.Ok(new[] { "Keyboard" }));
group.MapGet("/{id:int}", (int id) => Results.Ok(new { Id = id }));
10. Routing and HTTP Status Codes
- Attribute routing defines endpoint paths on controllers/actions.
- Constraints such as int and guid help select matching routes.
- Use route parameters for resource identity and query parameters for collection options.
- Use CreatedAtAction for a successful create response when a resource URL is available.
| Code | Meaning |
|---|---|
| 200 | OK |
| 201 | Created |
| 202 | Accepted for processing |
| 204 | Success, no response body |
| 400 | Bad Request / invalid input |
| 401 | Authentication missing or invalid |
| 403 | Authenticated but not permitted |
| 404 | Not Found |
| 409 | Conflict |
| 415 | Unsupported Media Type |
| 422 | Unprocessable Content |
| 429 | Too Many Requests |
| 500 | Unexpected server error |
| 503 | Service unavailable |
11. Model Binding and Validation
| Attribute | Source |
|---|---|
| [FromRoute] | Route values |
| [FromQuery] | Query string |
| [FromBody] | Request body, commonly JSON |
| [FromHeader] | HTTP headers |
| [FromForm] | Form fields |
| [FromServices] | Dependency injection |
public sealed class CreateProductRequest
{
[Required, StringLength(100, MinimumLength = 2)]
public string Name { get; init; } = "";
[Range(0.01, 100000)]
public decimal Price { get; init; }
}
- Use data annotations or custom validators for input rules.
- With [ApiController], invalid model state automatically produces a 400 response.
- Validate business rules separately from input shape.
- Always validate on the server, even if client-side validation exists.
- Authorization to a specific record is separate from validation.
12. DTOs, JSON and API Contracts
- Request DTOs define what clients may submit.
- Response DTOs control what the API reveals.
- Avoid returning EF Core entities directly when this exposes internal fields or creates serialization cycles.
- System.Text.Json is the default JSON serializer in ASP.NET Core.
- Treat JSON property names and response shapes as public API contracts.
- Version contracts deliberately when breaking changes are unavoidable.
public sealed record ProductResponse(int Id, string Name, decimal Price);
13. Dependency Injection
| Lifetime | Behavior | Typical use |
|---|---|---|
| Transient | New instance per resolution | Stateless helper |
| Scoped | One instance per request scope | DbContext and request service |
| Singleton | One instance for app lifetime | Thread-safe shared service |
builder.Services.AddTransient<IFormatter, Formatter>();
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddSingleton<IClock, SystemClock>();
Prefer constructor injection. Do not capture scoped services inside singletons. Singleton services must be thread-safe.
14. Middleware and Filters
- Middleware runs in the HTTP pipeline and can affect requests before and after endpoint execution.
- MVC filters run inside the MVC action/result pipeline.
- Use middleware for global exception handling, request logging and security headers.
- Use filters for MVC-specific authorization, action, exception or result concerns.
app.Use(async (context, next) =>
{
// Before the next component
await next();
// After the next component
});
15. Entity Framework Core and Data Access
- EF Core is an object-relational mapper for .NET.
- DbContext represents a unit of work and manages entity tracking.
- DbSet<T> represents a queryable entity collection.
- LINQ expressions are translated by the provider into database commands.
- Use async methods such as ToListAsync and SaveChangesAsync for I/O.
- Use projections, pagination and indexes to improve query efficiency.
- Do not run parallel operations on the same DbContext instance.
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
var rows = await db.Products.AsNoTracking()
.Where(p => p.IsActive)
.OrderBy(p => p.Name)
.Select(p => new ProductResponse(p.Id, p.Name, p.Price))
.ToListAsync();
16. CRUD Endpoint Design
| Operation | Endpoint | Typical response |
|---|---|---|
| List | GET /api/products | 200 |
| Read | GET /api/products/{id} | 200 or 404 |
| Create | POST /api/products | 201 Created |
| Replace | PUT /api/products/{id} | 200/204 or 404 |
| Partial update | PATCH /api/products/{id} | 200/204 or validation/conflict |
| Delete | DELETE /api/products/{id} | 204 or 404 |
Define PUT behavior consistently. PATCH requires a documented patch format and careful validation. Use consistent response semantics.
17. Relationships, Transactions and Concurrency
- EF Core supports one-to-one, one-to-many and many-to-many relationships.
- A transaction groups operations so they commit or roll back together.
- Optimistic concurrency detects whether data changed after it was read.
- Return a conflict response when a client must resolve a concurrent update.
- Avoid holding database transactions open during slow external network calls.
18. Error Handling and Problem Details
- Handle unexpected exceptions centrally.
- Do not expose stack traces or internal details to clients.
- Use consistent machine-readable error responses.
- Problem Details is a standard format for HTTP API errors.
- Log exceptions with trace/correlation identifiers and return safe messages.
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
Configure exception handling before endpoints and test both exception and status-code response paths.
19. Logging and Observability
- Use ILogger<T> and structured message templates.
- Log levels: Trace, Debug, Information, Warning, Error and Critical.
- Never log passwords, tokens or connection strings.
- Use correlation identifiers and distributed tracing across services.
- Monitor latency, throughput, error rates, dependencies and resource saturation.
- OpenTelemetry can standardize traces, metrics and logs when configured with exporters.
20. Authentication and Tokens
| Mechanism | Purpose |
|---|---|
| Cookie authentication | Protected browser session; common for server-rendered applications. |
| Bearer token | Client sends token in Authorization header. |
| JWT | Signed token format carrying claims; validate signature and claims. |
| OAuth 2.0 | Delegated authorization framework. |
| OpenID Connect | Authentication/identity layer built on OAuth 2.0. |
| API key | Shared client credential; protect, scope and rotate it. |
Authorization: Bearer <access-token>
Decoding a JWT is not validation. Validate signature, issuer, audience and lifetime through a trusted authentication handler. Prefer a trusted identity provider instead of implementing password/token systems from scratch.
21. Authorization: Roles, Claims and Policies
- Authentication identifies the caller; authorization decides what the caller may do.
- Roles group users such as Admin or Manager.
- Claims are statements about a user or client, such as department or permission.
- Policies combine requirements into named access rules.
- Resource-based authorization checks whether a caller may access a specific record.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("ManageProducts", policy =>
policy.RequireClaim("permission", "products.manage"));
});
[Authorize(Policy = "ManageProducts")]
Check authorization on every protected operation, not only in the user interface.
22. CORS, CSRF and HTTPS
- CORS is a browser-enforced cross-origin policy; it is not authentication or authorization.
- Allow only trusted origins, methods and headers. Avoid wildcard origins with credentials.
- CSRF is especially relevant when browsers automatically attach credentials such as cookies.
- Bearer-token APIs have a different CSRF profile, but still face XSS and token-storage risks.
- Use HTTPS in production and secure cookie attributes when cookies are used.
builder.Services.AddCors(options =>
{
options.AddPolicy("Frontend", policy =>
policy.WithOrigins("https://app.example.com")
.AllowAnyHeader().AllowAnyMethod());
});
app.UseCors("Frontend");
23. API Security Checklist
- Require HTTPS.
- Validate all untrusted input and enforce request-size limits.
- Authenticate callers and authorize every protected resource.
- Use DTOs to prevent over-posting/mass assignment.
- Store secrets outside source control.
- Use parameterized database access.
- Apply rate limits to public and sensitive endpoints.
- Restrict CORS to trusted origins where needed.
- Use safe error responses and avoid leaking internals.
- Patch runtimes and packages; scan dependencies.
- Protect file uploads and audit sensitive actions.
24. Pagination, Filtering, Sorting and Search
- Pagination limits response size and database work.
- Offset pagination uses page/pageSize or skip/take; enforce a maximum page size.
- Keyset/seek pagination can perform better for large, frequently changing data.
- Whitelist sortable fields; never concatenate arbitrary client input into SQL.
- Use stable ordering and return useful pagination metadata.
GET /api/products?page=1&pageSize=20&sortBy=name&sortDirection=asc&search=keyboard
25. File Uploads and Downloads
- Use multipart/form-data and IFormFile for conventional uploads.
- Enforce size limits at proxy, server and application layers.
- Generate server-side filenames; do not trust client filenames or extensions.
- Validate file content and scan where appropriate.
- Store untrusted uploads outside executable web-root locations.
- Authorize downloads and return safe content types and filenames.
26. Caching, Rate Limiting and Resilience
- Output caching stores endpoint responses under configured policies.
- Response caching follows HTTP cache semantics and headers.
- IMemoryCache is process-local; distributed caches share data across instances.
- Rate limiting controls request frequency/concurrency and can return 429.
- Retry only transient failures; account for idempotency.
- Use timeouts and circuit breakers where appropriate.
- Do not publicly cache private or user-specific responses.
27. API Versioning and OpenAPI
- Versioning manages API contract evolution. Common strategies: URL segment, query, header or media type.
- Choose one strategy and document it consistently.
- Avoid breaking changes where possible; deprecate old behavior deliberately.
- API versioning commonly uses a dedicated package; verify compatibility with .NET 10.
- OpenAPI describes endpoints, parameters, schemas, security and responses.
- ASP.NET Core has built-in OpenAPI support; interactive Swagger UI is a separate tooling choice and may require an additional package.
- Keep docs aligned with real behavior and do not expose development docs publicly by accident.
28. Health Checks and Diagnostics
- Liveness indicates the process is running.
- Readiness indicates the instance can receive traffic.
- Health checks can inspect databases and caches.
- Do not expose secrets or internal diagnostics through public health endpoints.
- Use metrics and traces to understand latency, failures and dependency behavior.
29. Testing
| Test type | Purpose |
|---|---|
| Unit | Test a component in isolation. |
| Integration | Test routing, middleware, services and data together. |
| Contract | Check provider/consumer compatibility. |
| End-to-end | Test a complete workflow. |
| Load | Measure behavior under expected/peak traffic. |
| Security | Test authentication, authorization and input controls. |
- WebApplicationFactory<TEntryPoint> supports ASP.NET Core integration tests.
- Test success, validation errors, missing resources, forbidden access, conflicts and unexpected failures.
- Use a test database/provider that reflects production behavior for database-sensitive tests.
30. API Testing Tools
- Swagger UI or another OpenAPI client can explore documented endpoints.
- Postman, Bruno, curl and HTTP files can send requests and inspect responses.
- Test headers, query parameters, JSON bodies, authentication and status codes.
curl -i https://localhost:5001/api/products
curl -i -X POST https://localhost:5001/api/products \\
-H "Content-Type: application/json" \\
-d "{\"name\":\"Keyboard\",\"price\":1200}"
31. Configuration and Environments
- appsettings.json contains general non-secret defaults.
- Environment-specific JSON files can override defaults.
- Environment variables and command-line arguments can override configuration.
- Use strongly typed options for related settings.
- Keep secrets out of source control.
- Common environments include Development, Staging and Production.
32. Deployment and Hosting
- Framework-dependent deployment expects a compatible runtime on the host.
- Self-contained deployment includes the runtime for a selected target platform.
- IIS commonly hosts ASP.NET Core on Windows using the ASP.NET Core Module.
- Linux deployments commonly use Kestrel behind a reverse proxy such as Nginx.
- Containers package the app and runtime dependencies.
- Cloud options include managed app services, virtual machines and container platforms.
dotnet publish -c Release
dotnet publish -c Release -r linux-x64 --self-contained true
Production readiness includes HTTPS, secrets, database migration planning, backups, monitoring, health checks, scaling, rollback and recovery procedures.
33. Performance and Scalability
- Use asynchronous I/O for database, file and network operations.
- Avoid blocking calls such as .Result and .Wait() in request paths.
- Project only fields required by the response.
- Use pagination and indexes matching real query patterns.
- Avoid N+1 query patterns.
- Set timeouts for requests and downstream dependencies.
- Measure with profiling, metrics and load tests before optimizing.
- Prefer stateless instances where possible for horizontal scaling.
34. Common Interview Comparisons
| Comparison | Difference |
|---|---|
| Web API vs MVC | API usually returns data; MVC commonly renders server-side views. |
| Authentication vs Authorization | Identity verification vs permission evaluation. |
| PUT vs PATCH | Replace representation vs partial modification. |
| 401 vs 403 | Missing/invalid authentication vs insufficient permission. |
| Middleware vs Filter | HTTP pipeline-wide vs MVC pipeline-specific. |
| Transient/Scoped/Singleton | Per resolution / per request scope / app lifetime. |
| IActionResult vs ActionResult<T> | Flexible result vs result with typed response contract. |
| CORS vs Authentication | Browser cross-origin policy vs caller identity. |
| Unit vs Integration | Isolated component vs multiple components together. |
35. Production Readiness Checklist
- Target framework and package versions are intentional and supported.
- HTTPS and production host configuration are correct.
- Authentication and resource-level authorization are tested.
- Validation, DTO mapping and safe error responses are implemented.
- CORS, rate limiting and request-size limits are appropriate.
- Secrets are stored outside source control.
- Database indexes, migrations and backups are planned.
- Logs, metrics, traces and health checks are available.
- Integration, security and load tests cover critical workflows.
- Deployment, rollback and incident response are documented.
How These Notes Fit the 30-Day Series
The 30-day series should teach one focused concept at a time with an example and exercise. These notes are the consolidated reference: they connect the topics, include supporting concepts that may not fit into a single daily post, and provide a revision path. Keep daily articles focused and link them to the relevant sections of this document.
Official Microsoft Resources
- https://learn.microsoft.com/aspnet/core/
- https://learn.microsoft.com/dotnet/
- https://learn.microsoft.com/aspnet/core/tutorials/first-web-api
- https://learn.microsoft.com/aspnet/core/security/
- https://learn.microsoft.com/aspnet/core/performance/
- https://learn.microsoft.com/aspnet/core/test/
- https://dotnet.microsoft.com/platform/support/policy/dotnet-core