Middleware in ASP.NET Core is a powerful mechanism for intercepting HTTP requests and responses during their lifecycle. With custom middleware, developers can handle tasks such as logging, exception handling, and authorization in a structured and reusable manner. This blog post will guide you through creating and extending middleware in ASP.NET Core, leveraging extension methods for improved modularity and readability.
What is Middleware?
Middleware is software injected into the request-response pipeline in ASP.NET Core applications. It processes HTTP requests as they flow through the pipeline, allowing developers to manipulate them before they reach the endpoint or after the endpoint has processed them.
Why Use Custom Middleware?
Centralizes logic like logging, error handling, and security checks.
Enhances maintainability by keeping concerns separate.
Simplifies reusability and testing.
Make sure you have the required package installed:
dotnet add package Microsoft.Extensions.DependencyInjection.Abstractions
Step 1: Setting Up Middleware Extension Methods
We define a static class MiddlewareExtensions to house all our middleware extension methods:
namespace gaurav.Middleware;
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseAuthorizationMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<AuthorizationMiddleware>();
}
public static IApplicationBuilder UseExceptionMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ExceptionMiddleware>();
}
public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LoggingMiddleware>();
}
}
Each method is a thin wrapper around UseMiddleware, ensuring that the middleware can be registered in the startup pipeline succinctly.
Step 2: Building the Middleware Classes
1. Authorization Middleware
This middleware handles authorization checks, ensuring that only authenticated users can access protected resources.
namespace gaurav.Middleware;
public class AuthorizationMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<AuthorizationMiddleware> _logger;
public AuthorizationMiddleware(RequestDelegate next, ILogger<AuthorizationMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, ISQLORMService sqlOrmService)
{
_logger.LogInformation("Processing authorization...");
// Implement authorization logic here
await _next(context);
}
}
2. Exception Middleware
This middleware provides a unified way to handle exceptions, log them, and return meaningful error responses to clients.
namespace gaurav.Middleware;
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context, ILogger<ExceptionMiddleware> logger)
{
try
{
await _next(context);
}
catch (Exception ex)
{
logger.LogError($"Unhandled exception: {ex}");
await HandleExceptionAsync(context, ex, Guid.NewGuid().ToString());
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception, string traceId)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
await context.Response.WriteAsync(new
{
statusCode = context.Response.StatusCode,
message = exception.Message,
traceId
}.ToString());
}
}
3. Logging Middleware
This middleware logs incoming requests and outgoing responses, providing valuable insights into the application's operation.
namespace gaurav.Middleware;
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context, ILogger<LoggingMiddleware> logger)
{
context.Request.EnableBuffering();
logger.LogInformation($"Incoming request: {context.Request.Method} {context.Request.Path}");
await _next(context);
logger.LogInformation($"Outgoing response: {context.Response.StatusCode}");
}
}
Step 3: Configuring Middleware in the Pipeline
To register custom middleware in the HTTP pipeline, use the extension methods in the Program.cs or Startup.cs file.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseLoggingMiddleware();
app.UseExceptionMiddleware();
app.UseAuthorizationMiddleware();
app.MapControllers();
app.Run();
Benefits of Middleware Extensions
Readability: Extension methods make pipeline configuration intuitive.
Reusability: Middleware can be reused across multiple applications.
Separation of Concerns: Each middleware handles a specific responsibility.
Conclusion
Custom middleware with extension methods streamlines your application's HTTP request pipeline. This approach not only enhances code readability but also aligns with the best practices of modular application design. By incorporating middlewares like logging, exception handling, and authorization, you can build robust and maintainable ASP.NET Core applications.
Feel free to extend this concept further with caching, rate-limiting, or custom headers as middleware!
Let me know in the comments how you use middleware in your projects or what custom middleware ideas you have! 🚀
Top comments (0)