ASP.NET Core is a cross-platform framework for building web apps and REST APIs on .NET.

Create a Web API Project

  dotnet new webapi -n MyApi
cd MyApi
dotnet run
  

Minimal API (Program.cs)

  var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapGet("/hello", () => "Hello, ASP.NET Core!");

app.MapGet("/users/{id:int}", (int id) =>
{
    return id > 0
        ? Results.Ok(new { Id = id, Name = $"User {id}" })
        : Results.BadRequest("Invalid id");
});

app.Run();
  

Controller-Based API

  [ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private static readonly List<Product> _products = new()
    {
        new(1, "Laptop", 999.99m),
        new(2, "Mouse", 29.99m),
    };

    [HttpGet]
    public ActionResult<IEnumerable<Product>> GetAll() => _products;

    [HttpGet("{id}")]
    public ActionResult<Product> GetById(int id)
    {
        var product = _products.FirstOrDefault(p => p.Id == id);
        return product is null ? NotFound() : Ok(product);
    }

    [HttpPost]
    public ActionResult<Product> Create(Product product)
    {
        _products.Add(product);
        return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
    }
}

record Product(int Id, string Name, decimal Price);
  

Middleware Pipeline

  app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
  

Middleware executes in order — each component can process the request, pass to the next, or short-circuit the pipeline.

Test endpoints with curl, Postman, or the built-in Swagger UI at /swagger.

Model Binding and Validation

  public record CreateProductRequest(string Name, decimal Price);

[HttpPost]
public IActionResult Create([FromBody] CreateProductRequest request)
{
    if (string.IsNullOrWhiteSpace(request.Name))
        return BadRequest("Name is required");
    if (request.Price <= 0)
        return BadRequest("Price must be positive");

    var product = new Product(0, request.Name, request.Price);
    _products.Add(product);
    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
  

For production apps, use FluentValidation or Data Annotations.

Dependency Injection in Minimal APIs

  builder.Services.AddScoped<IProductService, ProductService>();

app.MapGet("/products", async (IProductService service) =>
    Results.Ok(await service.GetAllAsync()));
  

Configuration from appsettings.json

  // appsettings.json
// { "ApiSettings": { "MaxPageSize": 100 } }

builder.Services.Configure<ApiSettings>(
    builder.Configuration.GetSection("ApiSettings"));

app.MapGet("/settings", (IOptions<ApiSettings> options) =>
    Results.Ok(options.Value));
  

Middleware Order Matters

  app.UseExceptionHandler("/error");  // first
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();               // last
  

Common Pitfalls

  • Returning void from controllers — always return IActionResult or ActionResult<T>.
  • Not enabling HTTPS redirection in production.
  • Hardcoding connection strings — use appsettings.json and user secrets locally.