ASP.NET Core middleware (sometimes called middleware, and other times referred to as intermediate software or modules) and it’s also the first post of our series. The reason I chose this topic is to explain the ease and possibilities new technologies provide, and also to dive a bit deeper into the subject.
I want to point out that during interviews, many people haven’t fully understood this topic. Unfortunately, this leads to architectural mistakes, especially in the Presentation layer related to SRP (Single Responsibility Principle).
When ASP.NET Core was built, it was designed with a modular structure. You’ll understand the modular part as you read further. ASP.NET Core uses a pipeline architecture style (incoming requests pass through specific middleware, and each middleware performs its own task. It’s not a design pattern or architectural pattern — it uses an architectural style, which I will discuss in another article). Thanks to the pipeline structure, we can create middleware, add it to the pipeline, and thus form the backbone of the application.
As a result, we can apply AOP (Aspect-Oriented Programming) features and add small modules, which helps us avoid code repetition and provides a flexible and expandable framework structure.
Of course, I know I have summarized this very briefly, but the goal is to explain the middleware structure. In another series, I will also touch on topics that intersect with middleware, like self-hosting, OWIN, and built-in features.
Let’s Start
Before diving into the details, middleware has two main functions:
- It can check whether to call the next middleware in the pipeline.
- It can perform actions either before or after the next middleware (Chain of Responsibility — COR).
ASP.NET Core is actually an abstract web framework. It provides us with an OWIN-based or application backbone that allows us to create a pipeline by attaching our own application as middleware.
When more than one middleware is added, each middleware in the pipeline is connected like a chain, and they can call each other. Structurally, it uses the Chain of Responsibility pattern, often shortened to COR or chain (I’ll sometimes use the word chain).
ASP.NET Core creates a response to an incoming request and sends it back to users (clients). Middleware is responsible for handling these incoming requests and responses as part of their tasks.
Frameworks are abstract by design. If we don’t add the MVC (web app) component to the pipeline, the application won’t give any result because there’s no middleware in the pipeline to process or handle it.
To work with MVC, we need to integrate the MVC middleware into the ASP.NET Core pipeline. This allows us to get results from our Controller/Action requests (the Controller is executed, returns a specific ActionResult, and this ActionResult is executed, writing the result to HttpResponse. The user then sees this). Alternatively, we can add our own custom middleware to process requests or responses and get results.
Before moving to examples, I want to note that we use the Chain of Responsibility (COR) pattern to create middleware!
Since middleware calls each other in a chain (I’ll use the word “chain” to make it easier for everyone to understand), they take an object of the RequestDelegate type. This object is the instance of the next or previous middleware in the chain (because of the chain structure), and it’s in your control whether to call the next one. In the following parts of my article, I’ll explain the types of middleware in more detail and how to use them in the chain.
There are two ways to create custom middleware in our applications:
Using the IMiddleware interface (strongly-typed middleware)
public class StrongyTypedMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
await context.Response.WriteAsync("Hello !");
}
}
Using a convention-based approach
public class ConventionBasedMiddleware
{
private RequestDelegate _next;
public ConventionBasedMiddleware(RequestDelegate next) { _next = next; }
public async Task InvokeAsync(HttpContext context)
{
await context.Response.WriteAsync("Hello !");
}
}
The InvokeAsync method must always be used, and as an input parameter, it must take an object of the HttpContext type. The return type of this method should be a Task.
For the middleware to work in a Chain of Responsibility (COR) style, it needs the next middleware object. This is optional — if you don’t want to call the next middleware, you don’t have to define it. This shows how flexible the middleware architecture can be.
Now, we will continue our article with examples of convention-based middleware.
What are the types of middleware?
In general, there are 4 types of middleware. These types are just abstract definitions, meaning that when creating middleware, certain functional abstract types are formed. The way these types are used is entirely based on the Chain of Responsibility (COR) pattern (the chain structure is demonstrated here).
The functional middleware types used in ASP.NET Core applications are:
- Response-editing middleware (edits the response)
- Request-editing middleware (edits the request)
- Short-circuiting middleware (stops the chain and doesn’t pass the request to the next middleware)
- Content-generating middleware (generates content or output)
, we transformed it to will come in, and our second middleware will analyze this URL and convert it into a format that MVC can understand.
Let’s conclude our article by registering all the middleware we have created in the ‘Configure’ method. All the added middleware is convention-based.
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHttpErrorHandler(); // 1. Response Editing middleware
app.UseRequestModifier(); // 2. Request Editing middleware
app.UseCacheResponse(); // 3. Short Circuit middleware
app.UseContentGenerator(); // 4. Content/Response generator middleware
}
I hope this has been helpful and that you have grasped the concept in a deeper way.
Stay tuned!
SOCIAL SHARE CARD GENERATOR