How to create REST APIs in ASP.NET Core?
Creating REST APIs in ASP.NET Core is straightforward using controllers or minimal
PIs.
Example: Traditional Controller-Based API
dotnet new webapi -n MyApi
Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
pp.MapControllers();
pp.Run();
Controller:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult GetAll() => Ok(new[] { "Laptop", "Phone"
});
}
✅ You get RESTful endpoints automatically (GET /api/products).
🧱 2. What is the [ApiController] attribute?
[ApiController] simplifies building APIs by adding smart defaults:
- Automatic model validation → 400 Bad Request on invalid models
- Automatic [FromBody], [FromQuery], etc. inference
- ProblemDetails JSON response for errors
Example:
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
[HttpPost]
public IActionResult CreateOrder(Order order)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
return CreatedAtAction(nameof(CreateOrder), new { id = 1 },
order);
}
}
📦 3. How does content negotiation work?
Content negotiation allows clients to request responses in a specific format (JSON, XML,
etc.) using the Accept header.
SP.NET Core automatically picks the best formatter:
GET /api/products
ccept: application/json
Response → JSON
GET /api/products
ccept: application/xml
Response → XML (if XML formatter is added)
Enable XML Support:
builder.Services.AddControllers()
.AddXmlSerializerFormatters();
🧭 4. How to handle versioning in APIs?
You can version APIs to maintain backward compatibility using the
Microsoft.AspNetCore.Mvc.Versioning package.
Install:
dotnet add package Microsoft.AspNetCore.Mvc.Versioning
Configure:
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
});
Use in controllers:
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsV1Controller : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok("Version 1");
}
⚠ 5. What is ProblemDetails?
ProblemDetails is a standardized JSON structure for API error responses (RFC 7807).
Example Output:
{
"type": "
"title": "Resource not found",
"status": 404,
"detail": "Product with ID 5 was not found"
}
Usage:
return NotFound(new ProblemDetails
{
Title = "Product not found",
Status = StatusCodes.Status404NotFound,
Detail = "The product ID 5 does not exist."
});
🚦 6. How to return custom HTTP status codes?
You can use built-in helpers from ControllerBase:
Method Status
Code
Ok() 200
Created() /
CreatedAtAction()
201
NoContent() 204
BadRequest() 400
Unauthorized() 401
NotFound() 404
StatusCode(500) Custom
Example:
return StatusCode(503, "Service temporarily unavailable");
📄 7. How to implement pagination in APIs?
Pagination helps manage large datasets efficiently.
Example:
[HttpGet]
public IActionResult GetProducts([FromQuery] int page = 1,
[FromQuery] int size = 10)
{
var data = _context.Products
.Skip((page - 1) * size)
.Take(size)
.ToList();
var totalCount = _context.Products.Count();
Response.Headers.Add("X-Total-Count", totalCount.ToString());
return Ok(data);
}
✅ Supports GET /api/products?page=2&size=5.
🔐 8. How to secure APIs with JWT tokens?
Use JWT (JSON Web Token) authentication for stateless security.
Setup in Program.cs:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationS
cheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new
TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "
ValidateAudience = true,
ValidAudience = "
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes("super-secret-key"))
};
});
Then protect controllers:
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
[HttpGet]
public IActionResult GetOrders() => Ok("Secure data");
}
⚡ 9. What is rate limiting in .NET 8?
.NET 8 introduces built-in rate limiting middleware to control API request rates.
Example:
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("fixed", opt =>
{
opt.PermitLimit = 5; // 5 requests
opt.Window = TimeSpan.FromSeconds(10); // per 10 seconds
opt.QueueLimit = 0;
});
});
var app = builder.Build();
pp.UseRateLimiter();
pp.MapGet("/api/data", () => "Hello")
.RequireRateLimiting("fixed");
✅ Prevents abuse or DDoS attacks by throttling requests.
🚨 10. How do you handle exceptions in APIs?
Use global exception handling middleware instead of try/catch everywhere.
Example:
pp.UseExceptionHandler("/error");
pp.Map("/error", (HttpContext context) =>
{
var exception =
context.Features.Get<IExceptionHandlerFeature>()?.Error;
return Results.Problem(title: "Unexpected error", detail:
exception?.Message);
});
Or write a custom middleware for consistent error formatting.
🧾 11. How to use Swagger / OpenAPI?
Swagger generates interactive API documentation automatically.
Setup:
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
pp.UseSwagger();
pp.UseSwaggerUI();
}
Run → Navigate to
✅ You can test endpoints directly from the browser.
🧰 12. What is NSwag or Swashbuckle?
Both tools generate OpenAPI/Swagger documentation, but with slight differences:
Tool Description
Swashbuckle.AspNetCor
Most common; adds Swagger UI, docs, and JSON schema
NSwag Adds extra features like client SDK generation for
C#/TypeScript
Example (NSwag client generation):
nswag openapi2csclient
/input:
/output:Client.cs
📤 13. How to upload files via Web API?
Use IFormFile for file uploads.
Controller Example:
[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("No file uploaded.");
var path = Path.Combine("wwwroot/uploads", file.FileName);
using var stream = new FileStream(path, FileMode.Create);
wait file.CopyToAsync(stream);
return Ok(new { file.FileName, file.Length });
}
Client sends multipart/form-data POST requests.
🌐 14. How to implement CORS?
CORS (Cross-Origin Resource Sharing) allows requests from other domains (e.g., frontend
pps).
Enable in Program.cs:
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowReactApp",
policy => policy.WithOrigins("
.AllowAnyHeader()
.AllowAnyMethod());
});
var app = builder.Build();
pp.UseCors("AllowReactApp");
✅ Now your React or Angular frontend can call your API safely.
🚀 15. What’s new in .NET 8 Minimal APIs?
Minimal APIs let you build lightweight REST endpoints without controllers — great for
microservices.
Example:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
pp.MapGet("/products", () => new[] { "Phone", "Tablet" });
pp.MapPost("/products", (Product product) =>
Results.Created($"/products/{product.Id}", product));
pp.Run();
New in .NET 8:
- Route groups for grouping endpoints
- Input validation with [Validate] attributes
- Enhanced OpenAPI (Swagger) support
- Rate limiting, Authorization, and Filters integration
- Typed results for consistent HTTP responses
✅ Minimal APIs now rival traditional controllers for small, fast APIs.
Performance & Caching