Filters & Middleware

Run code before and after every request. DRY principle for APIs.

The Rule: If you're writing the same code in 10 controllers, you're doing it wrong. Use Middleware or Filters.

1. The Zomato Problem - Why You Need This

Without Middleware: Log request time in 50 controllers. Change log format? Edit 50 files. Miss 1? Bug in prod.

With Middleware: Write logging once in Program.cs. Runs for every request. Change once. Done.

๐ŸŽฏ Real Example

Every Zomato API call logs: UserId, Endpoint, Time, StatusCode. 1 Middleware handles it for all 500 APIs. That's why their debugging is fast.

2. Middleware vs Filters - The 10 Second Decision

MiddlewareFilters
Runs WhenEvery HTTP request. Even if no controller.Only when request hits MVC/API controller.
OrderConfigured in Program.cs. You control exact order.Fixed pipeline: Auth โ†’ Action โ†’ Result.
Access ToHttpContext. Raw request/response.ActionContext. Knows controller, action, model.
Use ForLogging, Exceptions, Auth, CORS, Static FilesValidation, Caching, Custom Auth per action

Rule: App-wide concerns = Middleware. Controller-specific = Filter.

3. Code It: Global Exception Middleware

Goal: If any controller throws exception, return clean JSON {"error":"Server failed"} instead of HTML crash page.

// Middleware/GlobalExceptionMiddleware.cs
public class GlobalExceptionMiddleware {
  private readonly RequestDelegate _next;
  private readonly ILogger _logger;

  public GlobalExceptionMiddleware(RequestDelegate next, ILogger logger) {
    _next = next;
    _logger = logger;
  }

  public async Task InvokeAsync(HttpContext context) {
    try {
      await _next(context); // Call next middleware/controller
    }
    catch (Exception ex) {
      _logger.LogError(ex, "Unhandled exception");
      context.Response.StatusCode = 500;
      context.Response.ContentType = "application/json";
      await context.Response.WriteAsync("{\"error\":\"An internal server error occurred\"}");
    }
  }
}

// Program.cs - Order matters!
var app = builder.Build();
app.UseMiddleware(); // 1st - catches all errors
app.UseAuthentication(); // 2nd
app.UseAuthorization(); // 3rd
app.MapControllers(); // Last
app.Run();

Test: Throw new Exception() in any controller. API returns 500 JSON, not HTML. Logs error.

4. Code It: Action Filter for Logging

Goal: Log execution time for specific slow actions only.

// Filters/LogTimeAttribute.cs
public class LogTimeAttribute : ActionFilterAttribute {
  private Stopwatch _timer;
  public override void OnActionExecuting(ActionExecutingContext context) {
    _timer = Stopwatch.StartNew();
  }
  public override void OnActionExecuted(ActionExecutedContext context) {
    _timer.Stop();
    var logger = context.HttpContext.RequestServices.GetService>();
    logger?.LogInformation($"Action {context.ActionDescriptor.DisplayName} took {_timer.ElapsedMilliseconds}ms");
  }
}

// Controller usage
[HttpGet("slow-report")]
[LogTime] // Only this action gets timed
public IActionResult GetSlowReport() {...}
Career-Killer Mistake: app.UseExceptionHandler() AFTER app.MapControllers()
Result: Exception handler never runs. Controllers throw โ†’ crash โ†’ HTML error page.
Fix: Middleware is a pipeline. Order is critical. Exception handler must be FIRST. Auth must be before Controllers. Request flows down, response flows up.

Quick Check ๐Ÿง 

Middleware mastered. Next: CORS & Security Headers - Fix the "CORS error" every React dev hits, and add headers that get you A+ on security scans. Continue โ†’

Comments on Filters & Middleware (0)

No comments yet. Be the first to share your thoughts!