When building a web application or API, you will often hear the word middleware. It may sound complicated at first, but the idea behind middleware is actually very simple.
Middleware is software or code that runs between an incoming request and the main application logic.
It can inspect the request, modify it, allow it to continue, or stop it completely. Middleware can also work with the response before it is sent back to the user.
In simple words:
Middleware is code that sits in the middle of the request and response pipeline.
Understanding Middleware with a Simple Example
Imagine you are entering an office building.
Before you can meet someone inside, you may need to:
Enter through the main gate.
Show your ID to security.
Register at reception.
Get permission to enter a particular floor.
Finally meet the person you came to see.
A web application works in a similar way.
When a request reaches your application, it may need to pass through several checks before reaching the actual API or controller.
For example:
User
↓
HTTP Request
↓
Logging Middleware
↓
Authentication Middleware
↓
Authorization Middleware
↓
Rate Limiting Middleware
↓
Controller / API
↓
Database
↓
HTTP Response
↓
UserEach middleware performs a specific job.
How Middleware Works
Suppose your application has this API:
GET /api/usersA user sends a request to access it.
Instead of sending the request directly to the UsersController, the application may first send it through middleware.
Step 1: Logging
The first middleware records information about the request.
For example:
Method: GET
URL: /api/users
Time: 10:30:25 AM
IP: 192.168.1.10The request then continues.
Step 2: Authentication
The authentication middleware checks who is making the request.
For example, the request may contain a JWT token:
Authorization: Bearer eyJhbGciOi...The middleware validates the token.
If the token is valid, the request continues.
If it is invalid or expired, the middleware can return:
401 UnauthorizedThe controller is never called.
Step 3: Authorization
Authentication tells us:
Who are you?
Authorization tells us:
What are you allowed to do?
For example, the user may be authenticated but may not have permission to access the Admin API.
The middleware can return:
403 ForbiddenStep 4: Controller
If all middleware checks are successful, the request finally reaches the controller.
For example:
[HttpGet]
public IActionResult GetUsers()
{
return Ok(_userService.GetUsers());
}The controller processes the request and creates a response.
That response then travels back through the application and is returned to the client.
Middleware in ASP.NET Core
ASP.NET Core uses middleware heavily.
A typical Program.cs may contain code like this:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();Here, these lines are important:
app.UseAuthentication();
app.UseAuthorization();They add authentication and authorization middleware to the application pipeline.
The order in which middleware is added can be very important.
Middleware Pipeline
ASP.NET Core processes middleware in the order in which it is registered.
Consider:
app.UseMiddleware<MiddlewareA>();
app.UseMiddleware<MiddlewareB>();
app.UseMiddleware<MiddlewareC>();The request travels like this:
Request
↓
Middleware A
↓
Middleware B
↓
Middleware C
↓
ControllerThe response comes back in the opposite direction:
Controller
↓
Middleware C
↓
Middleware B
↓
Middleware A
↓
ResponseThis is why middleware is often described as a pipeline.
What Is next()?
When creating custom middleware, you will often see something called next.
For example:
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine("Request started");
await _next(context);
Console.WriteLine("Request completed");
}This line:
await _next(context);means:
Pass the request to the next middleware in the pipeline.
Anything before _next() runs while the request is moving toward the controller.
Anything after _next() runs while the response is coming back.
For example:
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine("Before API");
await _next(context);
Console.WriteLine("After API");
}The flow becomes:
Before API
↓
Controller executes
↓
After APIThis is one of the most important concepts to understand about middleware.
What Happens If Middleware Does Not Call next()?
Middleware does not always have to pass the request forward.
Suppose we create middleware that checks for an API key.
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.ContainsKey("X-API-Key"))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("API key is required.");
return;
}
await _next(context);
}If the API key is missing, this code returns:
401 Unauthorizedand stops processing.
The next middleware and controller are never executed.
This is called short-circuiting the pipeline.
It is useful for authentication, authorization, rate limiting, maintenance mode, IP blocking and many other situations.
Creating Custom Middleware in ASP.NET Core
You can also create your own middleware.
For example, let's create middleware that logs how long each request takes.
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
public RequestTimingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();
await _next(context);
stopwatch.Stop();
Console.WriteLine(
$"{context.Request.Method} " +
$"{context.Request.Path} " +
$"completed in {stopwatch.ElapsedMilliseconds} ms");
}
}Now register it:
app.UseMiddleware<RequestTimingMiddleware>();If someone calls:
GET /api/productsyou might see:
GET /api/products completed in 145 msThis can be very useful when troubleshooting API performance.
Common Uses of Middleware
Middleware is used for many important tasks in modern applications.
Authentication
Checks whether the user is logged in and validates credentials or tokens.
app.UseAuthentication();Authorization
Checks whether the authenticated user has permission to access a resource.
app.UseAuthorization();Logging
Records information about incoming requests, responses, errors and execution times.
Exception Handling
Instead of writing try/catch blocks everywhere, middleware can catch unhandled exceptions from the entire application.
For example:
app.UseExceptionHandler("/error");CORS
CORS middleware controls which websites or applications can call your API.
app.UseCors();Rate Limiting
Rate limiting middleware prevents clients from making too many requests within a short period.
For example:
Maximum: 100 requests per minuteIf the limit is exceeded, the server might return:
429 Too Many RequestsSecurity Headers
Middleware can add HTTP security headers to every response.
Request Modification
Middleware can add, remove or change information in an incoming request before it reaches the controller.
Response Modification
It can also modify the response before it is returned to the client.
Why Middleware Is Useful
Without middleware, you might need to repeat the same code in every controller.
Imagine writing authentication checks inside every API:
if (!IsAuthenticated())
{
return Unauthorized();
}You could have hundreds of endpoints.
Repeating this logic everywhere would make the application difficult to maintain.
Middleware solves this problem by moving common functionality into one central place.
Instead of:
Controller A → Authentication Code
Controller B → Authentication Code
Controller C → Authentication Code
Controller D → Authentication Codeyou can have:
Authentication
↓
┌─────────────┼─────────────┐
↓ ↓ ↓
Controller A Controller B Controller CThis makes the application cleaner and easier to maintain.
Middleware vs Controller
A common question is: why not put everything inside the controller?
The difference is responsibility.
Middleware usually handles functionality that applies to many or all requests, such as authentication, logging, error handling and security.
Controllers normally handle business functionality.
For example:
Middleware:
Validate JWT token
Controller:
Get customer's orders
Service:
Calculate order total
Database:
Retrieve order recordsKeeping these responsibilities separate makes the application easier to understand.
Middleware vs Filters in ASP.NET Core
Middleware and filters can sometimes appear similar, but they work at different levels.
Middleware works at the HTTP request pipeline level and can affect almost every request.
Filters work mainly around MVC controllers and actions.
For example, if you want to log every HTTP request, middleware is usually a good choice.
If you want special logic to run only before or after certain controller actions, a filter may be more appropriate.
Does Middleware Connect the Frontend and Backend?
This is another common misunderstanding.
Middleware does not simply mean software connecting a frontend and backend.
For example:
React / Angular / Next.js
↓
API
↓
ASP.NET Core
↓
DatabaseMiddleware normally exists inside the server-side request processing pipeline.
For example:
React Application
↓
HTTP Request
↓
ASP.NET Core
↓
CORS Middleware
↓
Authentication Middleware
↓
Authorization Middleware
↓
Controller
↓
Service
↓
DatabaseSo middleware is less about connecting two applications and more about processing communication as it passes through a system.
Middleware Exists Beyond .NET
Middleware is not an ASP.NET-only concept.
Many technologies use the same idea.
For example, Node.js with Express uses middleware:
app.use((req, res, next) => {
console.log("Request received");
next();
});Next.js also has middleware that can run before certain requests are completed.
Other platforms such as Java, Python frameworks, API gateways and cloud platforms use similar concepts.
The syntax changes, but the basic idea remains the same:
Request
↓
Middleware
↓
Application Logic
↓
ResponseReal-World Example
Imagine an e-commerce application with this endpoint:
POST /api/ordersA customer clicks Place Order.
The request might travel through:
Customer
↓
HTTPS Middleware
↓
Logging Middleware
↓
Rate Limiting Middleware
↓
Authentication Middleware
↓
Authorization Middleware
↓
Exception Handling
↓
Order Controller
↓
Order Service
↓
DatabaseThe controller does not need to worry about logging every request, validating the JWT infrastructure, applying global security policies or handling every unexpected exception.
Middleware handles these common concerns.
The controller can focus on what it is supposed to do:
Create the order.
Why Middleware Order Matters
One important thing developers should remember is that middleware order can change application behavior.
For example:
app.UseAuthentication();
app.UseAuthorization();makes sense because the application first needs to know who the user is before checking what the user is allowed to do.
Think of it like airport security.
First:
Who are you?Then:
Are you allowed to enter this area?Putting middleware in the wrong order can cause authentication, authorization, CORS, routing and other unexpected problems.
Final Thoughts
Middleware is one of the fundamental concepts behind modern web applications.
The easiest way to understand it is to think of middleware as a series of checkpoints that a request passes through before reaching the actual application logic.
A middleware component can:
Inspect the request
↓
Modify the request
↓
Allow it to continue
↓
Stop it if necessary
↓
Process the responseIn ASP.NET Core, middleware helps keep applications organized by handling common concerns such as authentication, authorization, logging, exception handling, CORS, security and rate limiting in centralized places.
If you remember only one thing, remember this:
Middleware is code that runs in the middle of the request and response pipeline, allowing applications to inspect, modify, control and protect HTTP requests before they reach the main application logic.

Join the conversation! Your thoughts help the community grow.