Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I saw some code lilke this:

public class CustomMiddleware {
    private RequestDelegate next;

    public CustomMiddleware (RequestDelegate nextDelegate) {
       next = nextDelegate;
    }
    
    public async Task Invoke(HttpContext context, IResponseFormatter formatter) {
       ...
       await next(context);
    }
}

and IResponseFormatter service is registered as:

public void ConfigureServices(IServiceCollection services) {
    services.AddTransient<IResponseFormatter, GuidService>();
}

I know how DI works, but my understanding how middleware works is, next(RequestDelegate) represents the next middleware's Invoke method, so in CustomMiddleware, even the second argument is resolved by DI, but the definition of RequestDelegate is

public delegate Task RequestDelegate(HttpContext context);

how does the previous middleware before CustomMiddleware knows that CustomMiddleware's Invoke method has changed by having an extra argument? It cannot know in advance, therefore the previous middleware's next RequestDelegate does't match the signature of CustomMiddleware's Invoke method?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
130 views
Welcome To Ask or Share your Answers For Others

1 Answer

How does the previous middleware before CustomMiddleware know that CustomMiddleware's Invoke method has changed by having an extra argument?

Because of convention (and reflection).

Custom Middleware doesn't inherit any interfaces or base classes, so the only way for the runtime to know how to use the middleware is by convention:

The middleware class must include:

  • A public constructor with a parameter of type RequestDelegate.
  • A method named Invoke or InvokeAsync. This method must:
    • Return a Task.
    • Accept a first parameter of type HttpContext.

With this knowledge, safely run the middleware: you can use reflection to get the dependencies of Invoke and execute it knowing the return type is Task. For example:

MethodInfo method = middleware.GetType().GetMethod("Invoke");
ParameterInfo[] parameters = method.GetParameters();
// ... instatiate the dependencies using something like ServiceProvider
// and bundle them up into an object[].
method.Invoke(middleware/**, injected dependencies go here as an object[] **/);

It cannot know in advance, therefore the previous middleware's next RequestDelegate does't match the signature of CustomMiddleware's Invoke method?

RequestDelegate does not match the signature of CustomMiddleware.Invoke.
RequestDelegate does not need to match the signature of CustomMiddleware.Invoke.

All the RequestDelegate (next) cares about is passing the same HttpContext instance down the middleware chain, and it will always have that because of the (previously mentioned) convention (emphasis added):

  • A method named Invoke or InvokeAsync. This method must:
    • Return a Task.
    • Accept a first parameter of type HttpContext.

Finally, next is not directly calling CustomMiddleware.Invoke. In between middlewares, DI has the opportunity to inject services needed for the next middleware.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...