Skip to main content

Middleware - Building Custom Request Processors

Level: Beginner

ℹ️ Where This Fits

Middleware is code that runs in the request pipeline. Learn this after the request pipeline and before routing details.

ℹ️ What You'll Learn
  • Middleware definition: Reusable code that runs on every request in the pipeline
  • Why middleware exists: Avoid repeating logging, auth, CORS, error handling in every route
  • app.Use(): Pass request to next middleware/endpoint (used for logging, timing, custom checks)
  • app.Run(): Terminal middleware that ends pipeline (last middleware, returns response)
  • app.Map(): Branch pipeline by path (e.g., /admin routes to admin middleware)
  • next parameter: Function that continues pipeline to next middleware
  • Before/after pattern: Code before await next() runs on request, code after runs on response
  • Middleware can stop request: Return without calling next() (e.g., authentication failure blocks request)
  • Built-in middleware examples: UseExceptionHandler, UseHttpsRedirection, UseStaticFiles, UseCors, UseAuthentication, UseAuthorization
  • Custom middleware class: Implements InvokeAsync(HttpContext context) method
  • School Management examples: Request logging middleware (logs GET /students), maintenance mode middleware, tenant detection middleware
  • Common mistakes: Forgetting await next(), calling next() twice, wrong middleware order
  • Performance consideration: Expensive middleware (database queries) should run after static files

What is Middleware?

Middleware is code that runs while a request is travelling through the ASP.NET Core pipeline.

It can:

  • Read request data
  • Log request details
  • Check authentication
  • Reject invalid requests
  • Call the next middleware
  • Modify the response
  • Catch errors

Simple mental model:

Request -> Middleware -> Middleware -> Endpoint -> Response

First Middleware Example

app.Use(async (context, next) =>
{
Console.WriteLine("Before endpoint");

await next();

Console.WriteLine("After endpoint");
});

context means current request and response.

next means "continue to the next middleware or endpoint".

Before and After Behavior

app.Use(async (context, next) =>
{
Console.WriteLine("1. Request entering logging middleware");

await next();

Console.WriteLine("4. Response leaving logging middleware");
});

app.MapGet("/", () =>
{
Console.WriteLine("2. Endpoint running");
return "Hello";
});

Output:

1. Request entering logging middleware
2. Endpoint running
4. Response leaving logging middleware

This is why middleware can do work both before and after your endpoint.

School Example: Request Logging

app.Use(async (context, next) =>
{
string method = context.Request.Method;
string path = context.Request.Path;

Console.WriteLine($"SchoolPortal Request: {method} {path}");

await next();

Console.WriteLine($"SchoolPortal Response: {context.Response.StatusCode}");
});

For:

GET /students/101

log:

SchoolPortal Request: GET /students/101
SchoolPortal Response: 200

Middleware Can Stop the Request

app.Use(async (context, next) =>
{
bool maintenanceMode = false;

if (maintenanceMode)
{
context.Response.StatusCode = 503;
await context.Response.WriteAsync("SchoolPortal is under maintenance");
return;
}

await next();
});

If middleware returns without calling next, the pipeline stops.

app.Use vs app.Run vs app.Map

MethodMeaningCalls Next?Use Case
app.UseAdd middlewareUsually yesLogging, auth, timing
app.RunTerminal middlewareNoEnd the pipeline
app.MapBranch pipeline by pathDependsSpecial path handling

app.Use

app.Use(async (context, next) =>
{
await next();
});

Use when request should usually continue.

app.Run

app.Run(async context =>
{
await context.Response.WriteAsync("This ends the pipeline");
});

Use carefully. It stops the pipeline.

app.Map

app.Map("/admin", adminApp =>
{
adminApp.Run(async context =>
{
await context.Response.WriteAsync("Admin area");
});
});

Use when a path needs a separate branch.

Built-In Middleware Examples

MiddlewarePurpose
UseExceptionHandlerHandles errors safely
UseHttpsRedirectionRedirects HTTP to HTTPS
UseStaticFilesServes CSS, JS, images
UseRoutingEnables routing
UseCorsAllows frontend apps from other origins
UseAuthenticationIdentifies the user
UseAuthorizationChecks permissions

Common Middleware Order

app.UseExceptionHandler("/error");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

Order matters because each middleware depends on what happened before it.

Custom Middleware Class

For bigger middleware, use a class.

public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;

public RequestTimingMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
var watch = System.Diagnostics.Stopwatch.StartNew();

await _next(context);

watch.Stop();
Console.WriteLine($"Request took {watch.ElapsedMilliseconds} ms");
}
}

Register it:

app.UseMiddleware<RequestTimingMiddleware>();

Real School Middleware Ideas

MiddlewareWhat It Does
Request loggingLog every API request
Request timingDetect slow attendance/report endpoints
Maintenance modeTemporarily block users during upgrades
Security headersAdd safe browser headers
Tenant detectionIdentify school/branch from request

Common Beginner Mistakes

MistakeProblem
Forgetting await next()Request stops early
Calling next() twicePipeline may behave incorrectly
Writing business logic in middlewareMiddleware should handle cross-cutting concerns
Wrong orderAuth, CORS, static files, and errors may break
Using app.Run too earlyRoutes after it may never execute

What to Remember

Middleware = reusable request/response processing step
next = continue pipeline
context = current request and response
order = very important
🎯 Interview Favourite

Q: What is middleware in ASP.NET Core?

Good Answer: "Middleware is a component in the ASP.NET Core request pipeline. It receives the current HttpContext, can inspect or modify the request, can stop the request, or can call next() to pass control to the next middleware. Middleware can also run code after the next component returns, so it can process both request and response. Common examples are logging, exception handling, static files, CORS, authentication, and authorization."

Practice Before Next Article

  1. Write middleware that logs request path.
  2. Write middleware that blocks /blocked.
  3. Explain app.Use vs app.Run.
  4. Explain why authentication comes before authorization.
  5. List three built-in middleware components.
🤖Use AI to Learn Faster

Use ChatGPT, Claude, or Copilot to go deeper on ASP.NET Core middleware. Try these prompts:

  • "Explain app.Use vs app.Run with examples"
  • "Give me a custom middleware for request timing"
  • "Why does middleware order matter?"
  • "What are common middleware interview questions?"

💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.

Next Article

-> Routing - Mapping URLs to Code

nexcoding.in