I've been trying to understand how ASP.NET 5 pipeline middlewares really work. A middleware, as I know, is just a Func<RequestDelegate, RequestDelegate>
, which is a pointer to a method that receives a reference to the next request delegate and returns a new one that wraps the next. We can of course, use a class to represent a middleware, something like:
public class MyMiddleware
{
private readonly _next;
public MyMiddleware(RequestDelegate next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
_next = next;
}
public Task Invoke(HttpContext context)
{
// New request delegate code here which can wrap the next one on the pipeline
}
}
Since the RequestDelegate
is a delegate that can hold references to methods which receives one HttpContext
and returns a Task
the Invoke
method is the request delegate to be returned and which has access to the next one on the pipeline.
We have then, when coding a middleware, access to the next component of the pipeline, but there is a doubt I have. In the beginning I thought the ideal was always to work the following way:
HttpContext
So that when I studied this for the first time I thought each middleware should always call the next one. But doing this led to strange behavior as discussed on this question.
Also looking at the source code of some middlewares I see some of them follow another steps:
HttpContext
and that's allIs this the real idea of using middlewares? Which way is the correct approach at this? Each middleware do what must be done with the request and always invoke the next or if a midleware can handle the request it doesn't invoke the next anymore?
I believe a middleware should call the next only if it can't handle the request. The reason I think that is because if not, there would be coupling between the middlewares on the pipeline. So that to process the request the middleware would need to be aware of what the previous one did to avoid messing everything. Is this conclusion right?
Middleware exist to make the request pipeline modular, meaning that you can add/remove/replace parts from it as long as you respect the contract. For example, if your application serves some files without any caching, you can add a middleware at the front of the pipeline without altering the rest. They are building blocks.
A middleware can:
Probably answering your other question too: there are two types of middleware:
Of course, some might do both depending on the context. For example auth can end the pipeline if the credentials are incorrect but continue otherwise.
The author of the middleware must decide if the next middleware (if any) should be invoked. In the case of the middleware in your question which returns a message, it should not invoke the next one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With