ASP.NET Core
01 / 03

Middleware, Routing & Configuration

ASP.NET Core: Middleware, Routing & Configuration

ASP.NET Core is a cross-platform, high-performance framework for building web APIs, web apps, and microservices. The request pipeline is built from middleware components chained together.

Program.cs — App Bootstrap

var builder = WebApplication.CreateBuilder(args);

// Register services
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

builder.Services.AddScoped<IArticleService, ArticleService>();
builder.Services.AddSingleton<ICacheService, RedisCacheService>();

var app = builder.Build();

// Middleware pipeline (order matters)
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();   // must be before UseAuthorization
app.UseAuthorization();

app.MapControllers();
app.Run();

Middleware

// Custom middleware (class-based)
public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var watch = Stopwatch.StartNew();
        _logger.LogInformation("Request {Method} {Path}", context.Request.Method, context.Request.Path);

        await _next(context);  // call next middleware

        watch.Stop();
        _logger.LogInformation("Response {StatusCode} in {Elapsed}ms",
            context.Response.StatusCode, watch.ElapsedMilliseconds);
    }
}

// Extension method for clean registration
public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder app)
        => app.UseMiddleware<RequestLoggingMiddleware>();
}

// Use in Program.cs
app.UseRequestLogging();

// Inline middleware (simple cases)
app.Use(async (context, next) =>
{
    context.Response.Headers["X-Content-Type-Options"] = "nosniff";
    await next(context);
});

// Terminal middleware (no next call)
app.Run(async context =>
{
    await context.Response.WriteAsync("Fallback response");
});

Configuration

// appsettings.json
// {
//   "ConnectionStrings": { "Default": "Server=...;Database=..." },
//   "JwtSettings": { "Secret": "...", "ExpiryMinutes": 60 },
//   "FeatureFlags": { "NewDashboard": true }
// }

// Bind to strongly-typed class
public class JwtSettings
{
    public string Secret { get; set; } = string.Empty;
    public int ExpiryMinutes { get; set; } = 60;
}

// In Program.cs
builder.Services.Configure<JwtSettings>(
    builder.Configuration.GetSection("JwtSettings"));

// In a service
public class TokenService
{
    private readonly JwtSettings _settings;

    public TokenService(IOptions<JwtSettings> options)
    {
        _settings = options.Value;
    }
}

// Read directly
var secret = builder.Configuration["JwtSettings:Secret"];
var connStr = builder.Configuration.GetConnectionString("Default");

// Environment overrides: appsettings.Development.json > appsettings.json
// Env vars override JSON: JWTSET__SECRET=value (double underscore = colon)
// Secrets manager (dev): dotnet user-secrets set "JwtSettings:Secret" "value"

Routing

// Attribute routing (controllers)
[ApiController]
[Route("api/[controller]")]    // → api/articles
public class ArticlesController : ControllerBase
{
    [HttpGet]                  // GET api/articles
    [HttpGet("{id:int}")]      // GET api/articles/42 (with constraint)
    [HttpGet("search")]        // GET api/articles/search
    [HttpGet("{id}/comments")] // GET api/articles/42/comments
    [HttpPost]                 // POST api/articles
    [HttpPut("{id}")]          // PUT api/articles/42
    [HttpDelete("{id}")]       // DELETE api/articles/42
}

// Route constraints
// {id:int}       — integer
// {id:guid}      — GUID
// {name:alpha}   — letters only
// {age:int:min(1):max(120)}
// {slug:regex(^[a-z0-9-]+$)}

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free