What is Middleware in ASP.NET Core MVC:
Middleware is a fundamental component in ASP.NET Core's request processing pipeline. Understanding it is essential for customizing how HTTP requests and responses are handled in your application.
Each middleware component:
-
Receives the HTTP request.
-
Performs some processing.
-
Optionally calls the next middleware in the pipeline.
-
Optionally modifies the HTTP response.
Middleware in ASP.NET Core Pipeline
The middleware pipeline is configured in Startup.cs (or Program.cs in .NET 6+).
For .NET Core 3.1/ASP.NET Core MVC:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Built-in middleware examples
app.UseDeveloperExceptionPage(); // 1. Show developer error page
app.UseStaticFiles(); // 2. Serve static files (CSS, JS)
app.UseRouting(); // 3. Enable routing
app.UseAuthentication(); // 4. Handle authentication
app.UseAuthorization(); // 5. Handle authorization
app.UseEndpoints(endpoints => // 6. Match request to controller/action
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Every middleware is a function that takes in:
HttpContext
A RequestDelegate (the next middleware)
Each middleware can decide:
To process and pass to the next middleware.
To short-circuit the pipeline.
Example of custom middleware:
public class MyCustomMiddleware
{
private readonly RequestDelegate _next;
public MyCustomMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// Before next middleware
Console.WriteLine("Request: " + context.Request.Path);
await _next(context); // Call the next middleware
// After next middleware
Console.WriteLine("Response: " + context.Response.StatusCode);
}
}
To register it in the pipeline:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<MyCustomMiddleware>();
}
🔹 Middleware Lifecycle (Request to Response)
Incoming Request:
Passes through all middleware in the order they are registered.
Terminal Middleware:
Ends the request without calling next (e.g., app.Run()).
Response:
Travels backward through middleware, allowing each to act on the response.
🔹 Built-in Middleware Examples
Middleware Purpose
UseStaticFiles() Serves static files like CSS, JS, images
UseRouting() Enables routing system
UseAuthentication() Handles user authentication
UseAuthorization() Checks user permissions
UseExceptionHandler() Centralized error handling
UseCors() Enables CORS (Cross-Origin Resource Sharing)
UseSession() Enables session state
UseEndpoints() Maps routes to endpoints (controllers)
🔹 When to Use Middleware?
Use middleware when:
You want to log request/response.
You want to perform actions globally, not tied to a specific controller.
You want to modify requests or responses.
You want to implement cross-cutting concerns like CORS, caching, auth, etc.
Example of Middleware to Create LoggerFile:
namespace FirstWebProject.Services
{
public class MyCustomMiddleware
{
private readonly RequestDelegate _next;
private readonly string path;
private static readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
public MyCustomMiddleware(RequestDelegate next)
{
_next = next;
path = Path.Combine(
Directory.GetCurrentDirectory(),
"mylogger.txt"
);
}
public async Task InvokeAsync(HttpContext context)
{
// Before next middleware
Console.WriteLine(
"Request: " + context.Request.Path
);
await WriteLogAsync(
$"REQUEST : {context.Request.Path} Time : {DateTime.Now}"
);
// Call next middleware
await _next(context);
// After next middleware
Console.WriteLine(
"Response Status: " + context.Response.StatusCode
);
await WriteLogAsync(
$"RESPONSE : {context.Request.Path} Status :
{context.Response.StatusCode} Time : {DateTime.Now}"
);
}
private async Task WriteLogAsync(string message)
{
await _lock.WaitAsync();
try
{
await File.AppendAllTextAsync(
path,
message + Environment.NewLine
);
}
finally
{
_lock.Release();
}
}
}
}
1. Create IpRestrictionMiddleware.cs
namespace FirstWebProject.Services
{
public class IpRestrictionMiddleware
{
private readonly RequestDelegate _next;
// Allowed IP addresses
private readonly string[] allowedIps =
{
"127.0.0.1",
"::1",
"192.168.1.10"
};
public IpRestrictionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
string userIp = context.Connection.RemoteIpAddress?
.ToString();
Console.WriteLine("User IP : " + userIp);
if (!allowedIps.Contains(userIp))
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync(
"Access Denied - IP Address Not Allowed"
);
return;
}
await _next(context);
}
}
}
2. Register middleware in Program.cs
Add before your routes:
app.UseMiddleware<IpRestrictionMiddleware>();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
Testing
If your IP is:
192.168.1.10
Output:
User IP : 192.168.1.10
Allowed
Any other IP:
User IP : 45.23.11.90
403 Forbidden
Access Denied - IP Address Not Allowed
For real login page restriction
If you want to restrict only /Account/Login:
public async Task InvokeAsync(HttpContext context)
{
if(context.Request.Path == "/Account/Login")
{
string ip = context.Connection.RemoteIpAddress?.ToString();
if(!allowedIps.Contains(ip))
{
context.Response.StatusCode = 403;
await context.Response.WriteAsync(
"Login blocked from this IP"
);
return;
}
}
await _next(context);
}

0 Comments
POST Answer of Questions and ASK to Doubt