synergetic
synergetic

Reputation: 8026

Asp.Net Core 2.x middleware syntax

I encountered several ways of writing simple middleware directly in Startup.Configure() method:

// Syntax 1.
app.Use((context, next) =>
{
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    return next();
});

// Syntax 2.
app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    await next();
});

// Syntax 3.
app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    await next.Invoke();
});

// Syntax 4.
app.Use(next =>
{
    return ctx =>
    {
        ctx.Response.Headers.Add("X-Content-Type-Options", "nosniff");
        return next(ctx);
    };
});

Are they all the same?

Upvotes: 11

Views: 1028

Answers (2)

Kahbazi
Kahbazi

Reputation: 14995

Syntax 4 is using Use method of IApplicationBuilder

IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)

Syntax 1, 2 and 3 are using an extension method for IApplicationBuilder which is a wrapper of previous method in Syntax 4. Here's the implimentation

public static IApplicationBuilder Use(this IApplicationBuilder app, Func<HttpContext, Func<Task>, Task> middleware)
{
    return app.Use(next =>
    {
        return context =>
        {
            Func<Task> simpleNext = () => next(context);
            return middleware(context, simpleNext);
        };
    });
}

For Syntax 2 and 3, there is no difference between next.Invoke() and next(). They both compile to the same method.

Upvotes: 6

Shaun Luttin
Shaun Luttin

Reputation: 141434

Syntax 1 and Syntax 2 are functionally different. Syntax 1 does not wait for next() to finish its Task. Syntax 1 is passing a normal lambda function to Use and is returning the Task without waiting for it to complete. Syntax 2 is passing an async lambda function and is awaiting the Task before returning. The await keyword tells the app to pause execution until the next() task is complete. In the code from your example, that might not lead to a functional difference, but there are times when waiting for a Task to complete can make a difference.

Syntax 2 and Syntax 3 are syntactically different and functionally identical. Syntax 2 is just a user-friendly versions of Syntax 3. See Func<T>() vs Func<T>.Invoke()

Syntax 1 and Syntax 4 are syntactically different and functionally identical. Syntax 1 is just a user-friendly wrapper around Syntax 4. See UseExtension.cs

// syntax 1,2,3 use this 
public static IApplicationBuilder Use(
    this IApplicationBuilder app, 
    Func<HttpContext, Func<Task>, Task> middleware)
{
    // which calls into syntax4
    return app.Use(next =>
    {
        return context =>
        {
            Func<Task> simpleNext = () => next(context);
            return middleware(context, simpleNext);
        };
    });
}

Upvotes: 7

Related Questions