A pipeline of middleware components in ASP.NET Core handles the processing of an incoming HTTP request. Run, Use, and Map are the techniques used to add/include and configure these middleware components in the pipeline.
run app.
app.Run() adds a terminal middleware to the request pipeline. Once this middleware executed, the pipeline is finished and no further middleware will run. Usually, it's the last middleware in your pipeline that handle the final response. Imagine it as the endpoint of your request processing. It's the middleware that finally returns the response to the client.
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello its the last middleware!");
});
Main features of app.Run():
- Terminal: It terminates the middleware pipeline.
- No next delegate available. The middleware given to app.Run() does not get a next delegate to transfer control to the next middleware.
- Last handler: Usually, it's the final middleware to handle the request and provide the answer.
app.Use
app.Use() adds middleware to the request pipeline that can potentially send control to the next pipeline middleware and process the request. This is the most common way to add middleware components.
Middleware added using app.Use() typically takes a delegate to the next middleware in the pipeline as an argument. Inside your middleware logic, you can perform actions before and after calling this next delegate.
app.Use(async (context, next) =>
{
Console.WriteLine("Before processing the request.");
await next.Invoke(); // Pass control to the next middleware
Console.WriteLine("After processing the request.");
});app.Run(async (context) =>
{
await context.Response.WriteAsync("Request handled by Run.");
});app.Run();
- The initial middleware records "Before processing the request."
- await nextInvoke() calls the next pipeline middleware—in this example, the one added by app.Run() runs the next middleware in the pipeline—in this case, the one added by app.
- The application.Run() middleware runs and delivers the response.
- Control goes back to the first middleware, which then records "After processing the request."
app.Map()
app.Map() branches the request pipeline depending on the request path. It lets you set up a different middleware pipeline that will run exclusively for requests matching a particular route prefix. You specify a path and a delegate that sets up a new middleware pipeline for that path. The request will be directed to this new pipeline if the incoming request path begins with the provided path.
app.Use(async (context, next) =>
{
Console.WriteLine("Middleware before Map.");
await next.Invoke();
Console.WriteLine("Middleware after Map.");
});app.Map("/admin", adminApp =>
{
adminApp.Use(async (context, next) =>
{
Console.WriteLine("Admin middleware before Run.");
await next.Invoke();
Console.WriteLine("Admin middleware after Run.");
});adminApp.Run(async context =>
{
await context.Response.WriteAsync("Admin area accessed.");
});
});app.Run(async context =>
{
await context.Response.WriteAsync("Default area.");
});app.Run();
Requests to /admin will be handled by the middleware configured within the adminApp delegate. Requests to other paths (e.g., /, /home) will bypass the /admin branch and will eventually be handled by the final app.Run() middleware,
Main features of app.Map():
- Path-based branching: Builds a distinct middleware pipeline for requests matching a particular path prefix.
- The middleware set up in the Map delegate only applies to requests inside that branch, thus creating an isolated pipeline. Main pipeline non-terminal:
- The main pipeline keeps processing requests not matching the mapped path.