Last Updated on July 13, 2025 by Aram
Middleware is the heartbeat of ASP.NET Core Applications.
To build a clear, scalable, and secure APIs, you have to know about the key collection of middleware that you should use.
So this article will shed the light on the top 10 Middleware in ASP.NET Core Web API that you have to know about.
And knowing the right ordering of the middleware in the ASP.NET Core pipeline is as important as using them.
So I will also be sharing with you the most important rules that you have to follow in order to avoid getting into troubles of debugging unexplained or unexpected behaviors after running your application.
So let’s get started:
The Top 10 Middleware in ASP.NET Core Web API
1. Forwarded Headers Middleware
You’re deploying behind a reverse proxy like NGINX or Azure App Gateway and want the actual client IP.
1 2 3 4 |
var app = builder.Build(); app.UseForwardedHeaders(); // code removed for brevity app.Run(); |
2. HTTPS Redirection Middleware
Redirects all HTTP requests to HTTPS automatically.
Use this middleware to secure sensitive API traffic, especially login and payment endpoints.
You can force users to access your banking or e-commerce app over secure HTTPS for data protection.
1 2 3 4 5 |
var app = builder.Build(); // code removed for brevity app.UseHttpsRedirection(); // code removed for brevity app.Run(); |
3. CORS Middleware
Cross-Origin Resource Sharing or CORS is responsible to relax the constraints set by the SOP – Same Origin Policy. This is why you have to use CORS wisely and carefuly to not allow unwanted connections to your API from sites that doesn’t have direction integration with your APIs, or even sites that you don’t trust.
So UseCors allow a frontend app on some domain to access your API on another domain.
This is also application for localhost, whenever you are running your API and your app on your same testing machine, you can test the CORS policies that you will define on the different ports that are connecting to your running API/App servers.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var builder = WebApplication.CreateBuilder(args); var codingSonataOrigin = "CodingSonataOrigin"; builder.Services.AddCors(options => { options.AddPolicy(name: codingSonataOrigin, policy => { policy.WithOrigins("http://codingsonata.com"); }); }); // code removed for brevity var app = builder.Build(); // code removed for brevity app.UseCors(codingSonataOrigin); // code removed for brevity app.Run(); |
4. Routing Middleware
Enables endpoint routing by matching the incoming request to configured routes for the associated controller or Minimal API endpoint.
Since .NET 6, apps don’t require to call UseRouting() manually since this is already handled from the WebApplicationBuilder.
However, UseRouting() can still be called explicitly to override the default behavior, so for instance you can call it after injecting a custom middleware
1 2 3 4 5 |
var app = builder.Build(); // code removed for brevity app.UseRouting(); // code removed for brevity app.Run(); |
5. Authentication Middleware
Authenticates users via JWT or cookie tokens.
Allow users to log and access protected resources only if authenticated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
var builder = WebApplication.CreateBuilder(args); // code removed for brevity builder.Services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "https://codingsonata.auth0.com/"; options.Audience = "https://api.codingsonata.com"; }); // code removed for brevity var app = builder.Build(); // code removed for brevity app.UseAuthentication() // code removed for brevity app.Run(); <!-- /wp:html --> <!-- wp:heading {"level":3} --> <h3 class="wp-block-heading">6. Authorization Middleware</h3> <!-- /wp:heading --> <!-- wp:paragraph --> <p>Authorization in ASP.NET Core come as role and policy-based, which are represented and validated using requirements against claims within handlers.</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>The authorization middleware enforces access policies for authenticated users with the use of [Authorize] attribute.</p> <!-- /wp:paragraph --> <!-- wp:html --> <pre> app.UseAuthentication(); app.UseAuthorization(); app.Run(); |
7. Rate Limiter Middleware
Rate limiting is very important measure to throttle the requests and only allow a certain number of requests at a given time window.
This can have multiple advantages from improving the performance, reducing costs of service usage, while reducing the possibility of major attacks on your APIs, like DDoS.
There are 4 types of rate limiting that can be configured through extension methods:
- Fixed Window
- Sliding Window
- Token Bucket
- Concurrency
Rate limiting can be either applied globally or via named policies where you can apply it to specific pages or endpoints.
The below applies 1 minute fixed rate limit for only 20 requests with 4 requests in queue.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var builder = WebApplication.CreateBuilder(args); builder.Services.AddRateLimiter(options => { options.AddFixedWindowLimiter("MyMinuteFixedLimit", opt => { opt.PermitLimit = 20; opt.Window = TimeSpan.FromSeconds(60); opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; opt.QueueLimit = 4; }); }); var app = builder.Build(); app.UseEndpoints(endpoints => { endpoints.MapControllers().RequireRateLimiting("MyMinuteFixedLimit"); }); |
8. Response Compression Middleware
Used to reduce the response payload size, this middleware compresses HTTP responses using common methods like Gzip, Deflate, or Brotli.
The general guideline here is that you should only compress responses that are not natively compressed.
Image assets like PNG or JPEG are natively compressed response. While HTML, CSS, JS are not natively compressed.
Keep in mind that adding compression to natively compressed responses will not give a good reduction in size while it will add the overhead of decompression, so the compression might cause reduction in performance.
1 2 3 4 5 6 7 8 9 |
var builder = WebApplication.CreateBuilder(args); // code removed for brevity builder.Services.AddResponseCompression(); // code removed for brevity var app = builder.Build(); // code removed for brevity app.UseResponseCompression(); // code removed for brevity app.Run(); |
9. Exception Handling Middleware
Catches unhandled exceptions and redirects to an error handling route or returns a formatted response.
In a production API, instead of exposing stack traces to users, redirect them to a friendly error page or return a JSON object with a generic error message.
Starting .NET 8, you can use the IExceptionHandler to easily implement a custom and generic exception handling middleware. Its simplicity comes from the method TryHandleAsync which provides a great abstraction for accessing the http context, the exception object, along with the ability to pass a cancellation token since it supports asynchronous programming.
Use this middleware to return a generic response message while still being able to pair it with Problem Details for an extensive and structured error response.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; public class MyHandler : IExceptionHandler { public async ValueTask<bool> TryHandleAsync( HttpContext context, Exception ex, CancellationToken ct) { var problemDetails = new ProblemDetails { Title = "An error occurred. Try again later.", Status = StatusCodes.Status500InternalServerError, Detail = ex.Message }; context.Response.StatusCode = problemDetails.Status.Value; await context.Response.WriteAsJsonAsync( new { message = "Server error" }, cancellationToken: ct ); return true; } } // Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddExceptionHandler<MyHandler>(); // code removed for brevity var app = builder.Build(); // code removed for brevity app.UseExceptionHandler(); app.Run(); |
10. Endpoints Middleware
Executes the endpoint by invoking the matched route handler which is selected by the routing middleware.
In other words, after UseRouting identifies the route, UseEndpoints triggers the controller’s action method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
var app = builder.Build(); // code removed for brevity app.UseRouting(); // code removed for brevity app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); <!-- /wp:html --> <!-- wp:heading --> <h2 class="wp-block-heading">Custom Middleware</h2> <!-- /wp:heading --> <!-- wp:paragraph --> <p>In addition to all the above, another middleware type which is as important as the above, is the custom middleware</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>this is where you write your own middleware and inject it into the pipeline. Also it depends on the type of action you are doing within the custom middleware that will guide you where you will inject the middleware.</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>A middleware where you will log your http requests and http responses can go somewhere early in the pipeline, but after the exception handler middleware, just to make sure any exceptions that you are gracefully handling will be properly logged afterwards.</p> <!-- /wp:paragraph --> <!-- wp:html --> <pre> public class RequestLoggingMiddleware( RequestDelegate next, ILogger<RequestLoggingMiddleware> logger ) { public async Task InvokeAsync(HttpContext context) { var method = context.Request.Method; var path = context.Request.Path; var ip = context.Connection.RemoteIpAddress?.ToString(); logger.LogInformation( "Incoming Request: {Method} {Path} from IP: {IP}", method, path, ip); await next(context); } } // Program.cs var app = builder.Build(); // code removed for brevity app.UseMiddleware<RequestLoggingMiddleware>(); // code removed for brevity app.Run(); |
12 Rules for Middleware Ordering in ASP.NET Core Web API
Below you can find the 12 rules for middleware orderning in ASP.NET Core.
Follow this ordering to stay on the safe side and avoid hours of debugging for unexpected behaviors after running your application.
- Use UseForwardedHeaders() first if behind a proxy.
- Force redirect to HTTPS early with UseHttpsRedirection().
- Call UseRouting() before any middleware that depends on route data.
- Apply UseCors() after routing but before authentication, and before response caching.
- Add UseAuthentication() before authorization.
- Always place UseAuthorization() after routing to enforce policies.
- Put UseExceptionHandler() near the top to catch all errors early.
- Set UseRateLimiter() early to shield your API from overload.
- Call UseResponseCompression() after routing and before endpoints.
- Register UseStaticFiles() before routing only if serving static content.
- Place custom middleware (e.g., logging, tracing) early to cover the full request.
- UseEndpoints() must be last to execute matched endpoints and terminate the pipeline.
Conclusion
Middleware is at the core of ASP.NET Core application, you need to know about the collection of top middleware that will power up your application, in this article we got introduced to the top 10 middleware in ASP.NET Core Web API.
References
- ASP.NET Core Middleware
- Write custom ASP.NET Core middleware
- .NET API Middleware for common functionality
Recent Posts
- Early Access to .NET 10 in Visual Studio 2022
- 6 Strategies to Build Resilience in ASP.NET Core
- Your Quick Guide to Learn JWT
Bonus
Enjoy this brilliant masterpiece of Italian Baroque music:
Arcangelo Corelli: Concerto grosso in D major, Op. 6 No. 1 – Bremer Barockorchester