Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A middleware should always invoke the next?

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:

  • Check if the middleware can handle the request
  • If it can, do whatever must be done with the HttpContext
  • Call the next middleware on the pipeline

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:

  • Check if the middleware can handle the request
  • If it can, do whatever must be done with the HttpContext and that's all
  • If not, and only if not call the next one

Is 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?

like image 569
user1620696 Avatar asked Mar 07 '15 02:03

user1620696


People also ask

What is invoke method in middleware?

Middleware is generally encapsulated in a class and exposed with an extension method. The middleware class must include: A public constructor with a parameter of type RequestDelegate. A public method named Invoke or InvokeAsync. This method must return a Task and accept the first parameter of type HttpContext.

What is the default order of invoking middleware on requests pipeline?

UseRouting , the Routing middleware runs at the beginning of the pipeline by default. For more information, see Routing. The order that middleware components are added in the Program. cs file defines the order in which the middleware components are invoked on requests and the reverse order for the response.

How does it get response to middleware when it comes to rest API calls?

Middleware gets executed after the server receives the request and before the controller actions send the response. Middleware has the access to the request object, responses object, and next, it can process the request before the server send a response.

How does middleware work in NET Core?

Middleware are software components that are assembled into an application pipeline to handle requests and responses. Each component chooses whether to pass the request on to the next component in the pipeline, and can perform certain actions before and after the next component is invoked in the pipeline.


1 Answers

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:

  1. Do nothing and pass the request further (e.g. a middleware that is applicable only to POST requests but the current one is GET)
  2. Do nothing to the request, do something else instead and pass it further (e.g. logging)
  3. Do something to the request and pass the request further (e.g. get an authentication token and convert it to an identity, or remove some sensitive information from the request)
  4. End the pipeline and not pass the request further (e.g. StaticFileMiddleware which just returns the file, or MVC when a route matches)

Probably answering your other question too: there are two types of middleware:

  1. Middleware that are designed to do something and pass the data along further (etc. auth, cookies, validation, logging etc)
  2. Middleware that complete the pipeline (static file, MVC, etc).

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.

like image 158
Victor Hurdugaci Avatar answered Oct 06 '22 23:10

Victor Hurdugaci