API Design | Dec 13, 2024 | 9 min read
Summarize
Middleware in ASP.NET Core powers tasks like logging and authentication, optimizing API functionality. Learn its basics and three ways to create it in .NET for scalable, maintainable APIs.
APIs have become the backbone of many applications. Why?
Because it provides a standardized way to exchange data and functionality between disparate systems.
As your API grows, it becomes increasingly important to ensure that your codebase remains organized, maintainable, and extensible.
One of the powerful tools available in NET for achieving this goal is middleware.
We'll explore the role of middleware in and how you can use it to extend the functionality of your API.
Firstly, I will grasp the basic concept of middleware. Then, we'll dive into how to create middlewares in .NET in 3 ways to handle common API-related tasks such as, for example, API key validation.
So, let's get started!
Middleware in ASP.NET Core is a powerful concept that allows you to create modular, reusable components that can augment the request/response pipeline of your web application. Is responsible for processing the request, potentially modifying it, and then passing it along to the next piece of middleware in the pipeline.
By leveraging middleware, you can add cross-cutting concerns, such as logging, authentication, and error handling, to your API without cluttering your actions or business logic.
Source: Microsoft documentation
The work of the middleware can be divided in 3 steps:
And there is no limitation on how much middleware you can chain together, but there is a strict rule about the order they are chained.
The order in which middleware is added to the pipeline plays a critical role in how requests and responses are processed. It’s essentially a sequential chain, where each middleware performs its task and decides whether to pass control to the next component. A slight misconfiguring the order can lead to unexpected behavior.
Source: Microsoft documentation
They are executed sequentially which means that they are executed in the same order they are registered. This determines how the incoming HTTP request flows through the pipeline.
Also, some middleware depends on others to run first. For example:
But they can also terminate the pipeline early by not calling the next middleware. Authorization middleware may block a request if the user lacks required permissions. This flow is called short-circuiting.
There is a two types of middlewares in .NET:
Let’s explore them in detail.
It refers to the predefined components that are provided by the framework to handle common concerns like authentication, routing, and more. These middleware are part of the NET request processing pipeline and are designed to handle specific tasks during the processing of HTTP requests and responses.
Some of built in middlewares at your disposal:
On the other hand, custom middleware refers to middleware components that developers create themselves to handle specific tasks that are not addressed by the built-in middleware.
They can be added to the request pipeline to implement application-specific logic, such as logging requests in a specific format, modifying request headers or handling particular business logic.
Two characteristic that are worth mentioning are:
In .NET there are three ways of creating custom middlewares:
Let’s explore them in detail now.
Simplest way is to use request delegates to create middleware. Request delegate is a function that processes HTTP requests. You can define middleware inline using request delegates with methods two methods:
They work differently, but both need to be called on a WebApplication instance.
Let’s first see how Run works.
The method is used to terminate the middleware pipeline and execute a terminal middleware component.
When you call the Run method, it sets the RequestDelegate
that will be executed when the middleware pipeline reaches that point.
The RequestDelegate
passed to is the last middleware component in the pipeline.
As you can see, the flexibility here is limited. And this is not a good approach if you want to have more than one middleware in the pipeline. That is where the Use method comes into place.
Use method registers middleware that can process incoming requests, call the next middleware, and act on outgoing responses. It has access to the HttpContext
and the next delegate for controlling the flow of the request pipeline.
Awaiting the next delegate allows the request to continue through the pipeline. To short-circuit the pipeline, simply avoid invoking the next delegate.
This approach is straightforward and simple, but it can make code bloated as the application grows.
Which leads to the second approach.
Convention-based middleware in .NET simplifies the process of defining and configuring middleware by leveraging established conventions instead of explicit configurations.
The established convention is:
Middleware class - represents created middleware
Class constructor: it accepts a RequestDelegate
parameter that allows the middleware to invoke the next component in the pipeline.
Invoke Method: Implement an Invoke
or InvokeAsync
method:
HttpContext
parameter to access request and response data.Integration: Use the middleware in the pipeline by adding it with the UseMiddleware<TMiddleware>()
extension method or a custom extension method.
This is how it look in the code:
And registration into pipeline:
Or you can use simpler approach, in my opinion to achieve same result:
This approach is a common way to create middleware. But there is one more way which is the most flexible and my personal favourite.
Third, and my personal favourite approach is a factory-based approach.
This involves creating middleware instances dynamically for each client request, enabling fine-grained control over middleware lifecycle and dependency injection.
For scoped or transient dependencies(per-request data or services) this can be the first choice in my opinion.
Here are the two key interfaces involved:
IMiddleware
instances.When middleware is registered in the DI container and implements the first interface, the framework runtime leverages the registered IMiddlewareFactory
to create and resolve instances, rather than relying on the default convention-based middleware activation process.
The implementation is can be divided in three steps:
Pretty simple and clean, right?
I also want to demystify what is this my preferred approach:
And just to be clear, this is not the “right way” of creating them. Just my personal preference. At the end, you should use the approach that fits your use case best.
I have shown you how to create middleware in all possible ways in .NET. But what are use cases for all three approaches? Let’s see:
Without the right tools, debugging and optimizing middleware can be a challenge.
This is where Treblle steps in.
One of Treblle's features is observability. It’s a real-time monitoring that captures request and response data as it flows through middleware, providing developers with immediate visibility into the API's behavior.
Additionally, Treblle’s error tracking feature helps pinpoint specific problems that may occur in the middleware pipeline by offering detailed logs and stack traces, making it easier to debug complex issues.
But it doesn't stop there—Treblle also provides valuable performance metrics that measure how long the middleware takes to process requests. This enables identifying potential bottlenecks, optimizing performance, and enhancing the overall efficiency of the application.
And the best part? A few lines of code is all it takes to integrate into an application.
Middlewares represents a powerful and flexible mechanism for extending and customizing API functionality. Whether you are using the built-in middleware or creating custom middleware to address the pipeline plays a crucial role in shaping the request-response lifecycle.
As APIs become increasingly complex, mastering middleware becomes crucial for building robust, scalable, and maintainable web applications that can adapt to evolving business requirements.
There are three ways to create and use middleware in .NET and the best option largely depends on your application's complexity and requirements.
But what is 100% true that middlewares bring is:
Middleware is key to creating APIs that are secure, efficient, and easy to maintain. With the right approach, you can ensure your application is ready to meet evolving challenges and scale effortlessly.
💡
Want to take your middleware and API performance to the next level? Try Treblle for real-time insights, error tracking, and optimization—all in one platform.
Shadow APIs are invisible threats lurking in your infrastructure—undocumented, unmanaged, and often unsecured. This article explores what they are, why they’re risky, how they emerge, and how to detect and prevent them before they cause damage.
APIs are the backbone of modern software, but speed, reliability, and efficiency do not happen by accident. This guide explains what API performance really means, which metrics matter, and how to optimize at every layer to meet the standards top platforms set.
MCP servers are the backbone of intelligent, context-aware AI applications. In this guide, you’ll learn what sets the best ones apart, explore practical use cases, and get tips for building and deploying your own high-performance MCP server.