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?
A middleware is nothing but a component (class) which is executed on every request in ASP.NET Core application. In the classic ASP.NET, HttpHandlers and HttpModules were part of request pipeline. Middleware is similar to HttpHandlers and HttpModules where both needs to be configured and executed in each request.
Middleware is software that's assembled into an app pipeline to handle requests and responses. Each component: Chooses whether to pass the request to the next component in the pipeline. Can perform work before and after the next component in the pipeline.
Now, we need to add our custom middleware in the request pipeline by using Use extension method as shown below. We can add middleware using app. UseMiddleware<MyMiddleware>() method of IApplicationBuilder also. Thus, we can add custom middleware in the ASP.NET Core application.
In a browser with developer tools enabled, make a request to the sample app with the path /redirect-rule/1234/5678 . The regular expression matches the request path on redirect-rule/(. *) , and the path is replaced with /redirected/1234/5678 . The redirect URL is sent back to the client with a 302 - Found status code.
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);
};
});
}
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.
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