ASP.NET Core Fundamentals
Introduction to ASP.NET Core for building web APIs and web applications
ASP.NET Core Fundamentals
ASP.NET Core is Microsoftβs modern web framework for building web applications, APIs, and microservices. Itβs cross-platform, high-performance, and widely adopted in enterprise environments.
What is ASP.NET Core?
ASP.NET Core is:
- Cross-platform β Runs on Windows, Linux, and macOS
- High-performance β One of the fastest web frameworks available
- Open-source β Developed openly on GitHub
- Modular β Only include what you need
Creating Your First API Project
1. Create the Project
# Create a Web API project
dotnet new webapi -n MyFirstApi
cd MyFirstApi
# Run it
dotnet run
Open your browser to http://localhost:5000/swagger to see the Swagger UI.
2. Project Structure
MyFirstApi/
βββ Controllers/
β βββ WeatherForecastController.cs
βββ Properties/
β βββ launchSettings.json
βββ appsettings.json
βββ appsettings.Development.json
βββ Program.cs
βββ MyFirstApi.csproj
3. Program.cs
In .NET 8, Program.cs is very minimal:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Controllers and Endpoints
Basic Controller
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
// GET api/products
[HttpGet]
public IActionResult GetAll()
{
var products = new[]
{
new { Id = 1, Name = "Laptop", Price = 999.99 },
new { Id = 2, Name = "Mouse", Price = 29.99 },
};
return Ok(products);
}
// GET api/products/1
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var product = new { Id = id, Name = "Laptop", Price = 999.99 };
return Ok(product);
}
// POST api/products
[HttpPost]
public IActionResult Create([FromBody] ProductDto product)
{
// Save to database
return CreatedAtAction(nameof(GetById), new { id = 1 }, product);
}
// PUT api/products/1
[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody] ProductDto product)
{
// Update in database
return NoContent();
}
// DELETE api/products/1
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
// Delete from database
return NoContent();
}
}
public record ProductDto(string Name, decimal Price);
HTTP Response Codes
return Ok(data); // 200
return Created(uri, data); // 201
return NoContent(); // 204
return BadRequest(); // 400
return Unauthorized(); // 401
return NotFound(); // 404
return Conflict(); // 409
Dependency Injection
ASP.NET Core has a built-in DI container:
1. Create a Service
// Interface
public interface IProductService
{
List<Product> GetAll();
Product? GetById(int id);
void Add(Product product);
}
// Implementation
public class ProductService : IProductService
{
private readonly List<Product> _products = new();
public List<Product> GetAll() => _products;
public Product? GetById(int id) => _products.FirstOrDefault(p => p.Id == id);
public void Add(Product product) => _products.Add(product);
}
2. Register in Program.cs
var builder = WebApplication.CreateBuilder(args);
// Register services
builder.Services.AddScoped<IProductService, ProductService>();
// ... rest of configuration
3. Use in a Controller
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
// Constructor injection
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
public IActionResult GetAll()
{
var products = _productService.GetAll();
return Ok(products);
}
}
Service Lifetimes
// Transient β created every time it's requested
builder.Services.AddTransient<IMyService, MyService>();
// Scoped β one instance per HTTP request
builder.Services.AddScoped<IMyService, MyService>();
// Singleton β one instance for the entire application
builder.Services.AddSingleton<IMyService, MyService>();
Validation
Model with Data Annotations
using System.ComponentModel.DataAnnotations;
public class CreateProductDto
{
[Required(ErrorMessage = "Product name is required")]
[StringLength(100, MinimumLength = 3)]
public string Name { get; set; }
[Required]
[Range(0.01, 1000000, ErrorMessage = "Price must be between 0.01 and 1,000,000")]
public decimal Price { get; set; }
[EmailAddress]
public string? SupplierEmail { get; set; }
}
Validation in a Controller
[HttpPost]
public IActionResult Create([FromBody] CreateProductDto dto)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Process...
return Ok();
}
Configuration
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyDb;..."
},
"AppSettings": {
"ApiKey": "secret-key",
"MaxPageSize": 100
}
}
Accessing Configuration
// In Program.cs
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
// Options Pattern
public class AppSettings
{
public string ApiKey { get; set; }
public int MaxPageSize { get; set; }
}
builder.Services.Configure<AppSettings>(
builder.Configuration.GetSection("AppSettings"));
// In a service/controller
public class MyService
{
private readonly AppSettings _settings;
public MyService(IOptions<AppSettings> options)
{
_settings = options.Value;
}
}
Middleware
Middleware are components that process HTTP requests and responses:
var app = builder.Build();
// Built-in middleware
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
// Custom middleware
app.Use(async (context, next) =>
{
// Before the request is processed
Console.WriteLine($"Request: {context.Request.Path}");
await next();
// After the response is created
Console.WriteLine($"Response: {context.Response.StatusCode}");
});
app.MapControllers();
Minimal APIs (.NET 6+)
A simpler alternative to controllers:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Simple endpoints
app.MapGet("/", () => "Hello World!");
app.MapGet("/products", () =>
{
return new[] { new { Id = 1, Name = "Laptop" } };
});
app.MapGet("/products/{id}", (int id) =>
{
return new { Id = id, Name = "Laptop" };
});
app.MapPost("/products", (ProductDto product) =>
{
return Results.Created($"/products/1", product);
});
app.Run();
record ProductDto(string Name, decimal Price);
Best Practice Tips
- Use DTOs β Donβt expose database entities directly through your API
- Async/Await β Use for all I/O operations
- Exception Handling β Use middleware for global error handling
- Logging β Use the built-in ILogger
- Versioning β Implement API versioning from the start
Next Steps
- Entity Framework Core β Connect to a database
- Authentication & Authorization β Secure your API
- Testing β Unit and integration testing
ASP.NET Core is a very powerful framework. Start simple, then increase complexity as needed.