milandjukic88
milandjukic88

Reputation: 1115

How does one middleware call another?

I'm learning ASP.NET Core and I'm stuck. I understand that one middleware calls another and I know how, but I don't understand under the hood.

See this code:

app.Use(async (context,next) =>
{
   await next();
});

app.Run(async (context) =>
{
   await context.Response.WriteAsync("Hello from 2nd middleware!");
});

A week ago I've learned Threading and Tasks in C# and now I'm trying to comprehend this. First middleware is called and it calls the second one with await next();. But how does it know what is second?

Upvotes: 1

Views: 1373

Answers (2)

mtanksl
mtanksl

Reputation: 591

K. Scott Allen has the answer How the Next Delegate Works In ASP.NET Core Middleware.

Basically next() returns a delegate that points to the next middleware in the list. The list is build when you use app.Use, app.Run or app.UseMiddleware.

public class MiddlewareComponentNode
{
    public RequestDelegate Next;
    public RequestDelegate Process;
    public Func<RequestDelegate, RequestDelegate> Component;
}

LinkedList<MiddlewareComponentNode> Components = new LinkedList<MiddlewareComponentNode>();

public void Use(Func<RequestDelegate, RequestDelegate> component)
{
    var node = new MiddlewareComponentNode
    {
        Component = component
    };
 
    Components.AddLast(node);
}

public RequestDelegate Build()
{
    var node = Components.Last;
    while (node != null)
    {
        node.Value.Next = GetNextFunc(node);
        node.Value.Process = node.Value.Component(node.Value.Next);
        node = node.Previous;
    }
    return Components.First.Value.Process;
}
 
private RequestDelegate GetNextFunc(LinkedListNode<MiddlewareComponentNode> node)
{
    if (node.Next == null)
    {
        return ctx =>
        {
            ctx.Response.StatusCode = 404;
            return Task.CompletedTask;
        };
    }
    else
    {
        return node.Next.Value.Process;
    }
}

var pipeline = Build();     
var request = new TestHttpContext();
pipeline(request);

Upvotes: 0

Lior
Lior

Reputation: 508

According to Microsoft:

The order that middleware components are added in the Startup.Configure method defines the order in which the middleware components are invoked on requests and the reverse order for the response.

The ApplicationBuilder is hold IList of components that contains the components you add when you call .Use(), .Run(), .Map(). And as you probably know list is preserve order.

For more information: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-3.1

Upvotes: 2

Related Questions