Middleware in programming is a crucial concept that can sometimes be challenging to understand. In the blog post below, I will try to clarify and make it simple to understand using the .NET framework.
To better understand this complex concept, let’s take as an example the process of building a house. I am no house builder by any means, but when a house is built there are some steps that are followed in a certain order. Each step is handled by a group of skilled workers who are experts in their specific tasks. A list of simplified steps would be like below:
- Foundation workers – they prepare the ground and create a strong base for the house. This is the first step of the process of building the house. Without this step, other works can not move to the next one.
- Framing workers – they build the frame that forms the shape of the house
- Roof workers – they install the roof to protect the house from rain and other elements
- Plumbers – they set up all the water-related tasks, like water pipes, the drainage system, etc.
- Electricians – they set up all the electricity-related tasks, like installing wiring, switches, and outlets for electricity
- Painters – they paint the walls, ceiling, and all the other surfaces to make the hours look nice, fresh, and clean
- Landscapers – they will do the last set of tasks before the house owner gets the keys. They will plant trees, flowers, and grass around the house to make it more attractive and a nice place to live in.
As you can see it takes different sets of work to do different tasks in a certain order for the house to be built from the ground up. You can modify the same example for the car-building process, ordering food in a restaurant, etc.
In the .NET world, your request to build a house is like a message that gets passed through a series of helpers (middlewares). Each helper (middleware) does a specific job/task in the process, and they need to work together in the correct order to build the house successfully (process your request successfully).
Similar to once all the workers have completed their task, you have a complete house, in .NET once all the helpers (middleware) have completed their task you will have a complete response built according to your needs.
In other words just like skilled workers help you build a house, .NET middleware helps organize and process the messages your app sends and receives. Each middleware has a specific job, and they work together to make everything run smoothly.
Let’s now build APIs…
Now, instead of building a house, imagine you’re building an application that receives requests to display a list of products. Your middleware chain might look like this:
- Logging middleware (worker/helper): Logs the incoming request details.
- Authentication middleware (worker/helper): Checks if the user is authorized to access the requested resource.
- Caching middleware (worker/helper):: Checks if the list of products is cached, and if so, returns it without proceeding further in the chain.
- Response formatting middleware (worker/helper):: Formats the response (e.g., JSON, XML) before sending it back to the client.
As you can see above, once you do the request, .NET will pass your request through different .NET Middleware helpers which are called in a specific order and need to be called successfully for the request to be executed successfully.
In .NET there are a set of default middleware helpers that come out of the box, but which are some of these middlewares?
Default Middlewares
There are lots of default .NET middleware, but here I will talk about the commonly used ones.
- Static files middleware
This middleware is used to handle requests for static files, such as HTML, CSS, JavaScript, and images.
In .NET there is a default folder named “wwwroot”, so if you want to serve static files from this folder you can add the static files middleware configuration to your app.
In .NET 6+ to do that, in Program.cs you can add this line of code:
app.UseStaticFiles();
- Routing middleware
This middleware allows your application to map incoming requests to the appropriate action methods in controllers. If you want to map an incoming request with a path like “/api/articles” to a method called “GetBlogArticles” in the “ArticlesController” you can use the line below:
app.UseRouting();
- Authentication middleware
This middleware provides authentication services, such as checking if a user is signed in and managing user identities. If you want to support cookie-based or token-based authentication in your apps, then you need to add the following line in the middleware configuration in the Program.cs in .NET 6+ application or in the Startup.cs file, Configure method in the .NET apps lower than .NET 6.
app.UseAuthentication();
- Authorization middleware
The Authentication middleware adds authentication services to the .NET application, but if you want to handle authorization by checking if an authenticated user has the necessary permissions to access a specific resource you can use the authorization middleware.
For that, you can use the following line:
app.UseAuthorization();
- CORS middleware
Implements Cross-Origin Resource Sharing (CORS) policies, enabling your application to specify which domains can access its resources. It’s added using
app.UseCors()
How Does It All Works?
In .NET, middlewares are orchestrated through a concept known as middleware pipeline. Think of the middleware pipeline as the construction builder, who orchestrates the work of all the different workers to build houses. Similarly the middleware pipeline is a sequence of components (middlewares) that are executed in a specific order to process incoming HTTP requests and generate responses. Each middleware in the pipeline (worker) is responsible for a specific task, such as routing, authentication, or serving static files (building foundation, framing, painting, gardening, etc.).
In .NET 7, the middleware pipeline concept remains largely the same as in previous versions of ASP.NET Core. However, the way you configure and set up the middleware pipeline is slightly different from the introduction of the WebApplicationType.
Middlewares are registered and configured in the Program.cs file. You create a WebApplication builder to add and configure middlewares using extension methods like UseRouting(), UseAuthentication(), etc.
Example
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); // ... Other middleware. app.UseRouting(); // Add the routing middleware. app.UseAuthentication(); // Add the authentication middleware. app.UseAuthorization(); // Add the authorization middleware. // ... Other middleware.
When an HTTP request comes in, it is passed through the middleware pipeline. Each middleware in the pipeline is executed in the order they were added. A middleware can choose to pass the request to the next middleware
Benefits
.NET middleware is a concept in the .NET framework that helps manage the flow of requests and responses between a client app (e.g., a browser-based app or a mobile app) and the server where your application is hosted.
We have discussed middlewares, the middleware pipeline, and some key concepts, but what are the primary benefits of using middlewares in .NET?
If we were to summarize the importance of .NET middleware in three bullet points, we would have the following points:
- Modularization of code: Middleware components can be developed, tested, and maintained independently, promoting separation of concerns and reusability.
- Customization of pipeline: You can create your own middleware functions to add custom functionality, or use pre-built middleware to handle common tasks like logging, exception handling, or serving static files.
- Enhance performance and security: Middleware can be used to implement caching, authentication, and data compression, improving the overall performance and security of your application.