blog post

Getting Started with Middlewares in ASP.NET Core

ASP.NET Core's middleware architecture offers a powerful way to build and configure the HTTP request pipeline in your applications. In this post, you'll explore what middleware is, the correct order of middlewares, and discuss some of the most widely used middlewares.

What is Middleware in ASP.NET Core?

Middleware in ASP.NET Core is a software components that is a part of application pipeline that handles requests and responses. In ASP.NET Core there are multiple middlewares that are combined in a chain with each other. Each middleware component in the pipeline is responsible for invoking the next component in the sequence. Any middleware can stop other middlewares from execution by short-circuiting the chain if necessary. Middlewares in ASP.NET Core is a classic implementation of chain of responsibility design pattern.

Creating a middleware in ASP.NET Core is straightforward. All you need to do is to call a Use method on the WebApplication object:

csharp
var builder = WebApplication.CreateBuilder(args); builder.Logging.AddConsole(); var app = builder.Build(); app.Use(async (context, next) => { var logger = context.RequestServices.GetService<ILogger<Program>>(); logger?.LogInformation("Request is starting..."); await next.Invoke(); logger?.LogInformation("Request has finished"); }); app.MapGet("/api/books", () => { var books = SeedService.GetBooks(10); return Results.Ok(books); }); await app.RunAsync();

In this example when calling a /api/books endpoint, the middleware declared in the Use method is called first. await next.Invoke() calls the books endpoint itself, but before and after we have a message logged to console.

Middlewares are executed in the order they are added to the pipeline in the WebApplication object. Each middleware can perform operations before and after the next middleware:

Before: executing operations before calling the next middleware can include tasks like logging, authentication, validation, etc.
After: operations after calling the next middleware can include tasks like response modification or error handling.

The real power of middlewares is that you can chain them freely in any order you want. To stop the request from executing and short-cut the middleware chain (stop other middlewares from executing) - write a response directly into HttpContext instead of calling the await next.Invoke() method:

csharp
await context.Response.WriteAsync("Some response here");

The Most Common Built-in Middlewares in ASP.NET Core

ASP.NET Core has a lot of built-in middlewares and many provided by Nuget packages. Let's explore the most common middlewares:

  • UseExceptionHandler: first in the pipeline to catch and handle exceptions thrown in later stages.
  • UseRateLimiter: limits the number of requests a client can make in a given time.
  • UseHsts: enforces the use of HTTPS in the application.
  • UseHttpsRedirection: redirects HTTP requests to HTTPS.
  • UseStaticFiles: serves static files and should come before any dynamic processing.
  • UseHttpLogging: logs HTTP request and response data.
  • UseForwardedHeaders: processes headers from load balancers, forwarding and reverse proxies.
  • UseRouting: determines the routing of the application.
  • UseCors: manages Cross-Origin Resource Sharing policies.
  • UseAuthentication: manages user authentication.
  • UseAuthorization: manages user authorization.
  • UseOutputCache: stores responses to cache for performance improvement.
  • Swagger (only for development): provides a UI with documentation for the Web API.
  • Map... Methods: maps the incoming requests to appropriate endpoints.
  • Fallback: provides a handler for unmatched routes.

Understanding the Correct Order of Middlewares

The order in which middlewares are added to the application pipeline is critical. It defines how the incoming HTTP requests travel through the pipeline and in what sequence the responses are sent back.

Middlewares are executed in the order they are added to the pipeline in the WebApplication object.

Here is a typical order of middleware registration in an ASP.NET Core application:

csharp
var app = builder.Build(); app.UseExceptionHandler(_ => {}); app.UseRateLimiter(); app.UseHsts(); app.UseHttpsRedirection(); app.UseResponseCaching(); app.UseResponseCompression(); app.UseStaticFiles(); app.UseHttpLogging(); app.UseForwardedHeaders(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseOutputCache(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapControllers(); app.MapHealthChecks("/health"); app.Use(async (context, next) => { // Custom middlewares here }); app.MapGet("/api/books", () => { var books = SeedService.GetBooks(10); return Results.Ok(books); }); app.MapFallbackToFile("wwwroot/index.html"); await app.RunAsync();

When the webapp receives an HTTP request, UseExceptionHandler middleware is the first to go, going down in the order these middlewares are defined in Program.cs. When the Minimal API or Controller endpoint is executed (books are retrieved in this example) the response comes up in the chain of middlewares. Here are some of the important tips when placing the middlewares:

  • UseExceptionHandler is placed as first middleware to handle any errors occured in our http endpoints or other middlewares.
  • Here we use UseHttpLogging middleware down after the UseResponseCompression. It means that after executing the endpoint, response with books is correctly logged before being compressed. If UseHttpLogging was placed before the UseResponseCompression we would end up with a mess of bytes and symbols in the response log instead of a readable json.
  • When an HTTP endpoint requires authentication and the request doesn't provide valid auth credentials: the UseAuthentication endpoint breaks the chain of middlewares and returns 401 Unauthorized response.
  • UseOutputCache is placed after the authentication and authorization middlewares to make sure that only authenticated and authorized client can get the cached response.

Summary

Middlewares are a powerful feature in ASP.NET Core, offering developers the flexibility to customize the request pipeline to suit the application's needs. Understanding and correctly configuring middlewares ensure your application handles requests and responses efficiently while maintaining security and performance.

Hope you find this blog post useful. Happy coding!

Improve Your .NET and Architecture Skills

Join my community of 1800+ developers and architects.

Each week you will get 2 practical tips with best practises and architecture advice.