From 6df59db5058398f213723ff34969d1db46b495ea Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:16:20 -0500 Subject: [PATCH 01/16] Middleware article overhaul --- .../blazor/host-and-deploy/app-base-path.md | 2 +- aspnetcore/data/ef-rp/update-related-data.md | 4 - aspnetcore/fundamentals/app-state.md | 4 +- aspnetcore/fundamentals/http-requests.md | 1 - .../localization/includes/localization35.md | 2 - aspnetcore/fundamentals/middleware/index.md | 209 ++++++- .../middleware/index/includes/index3-7.md | 556 +++++++++++++++++- .../index/snapshot/Chain/Startup.cs | 17 - .../index/snapshot/Chain/StartupMap.cs | 30 - .../index/snapshot/Chain/StartupMapWhen.cs | 22 - .../index/snapshot/Chain/StartupMultiSeg.cs | 20 - .../index/snapshot/Chain/StartupUseWhen.cs | 26 - .../index/snapshot/Chain60/Program.cs | 16 - .../index/snapshot/Chain60/ProgramMap.cs | 29 - .../index/snapshot/Chain60/ProgramMapWhen.cs | 20 - .../index/snapshot/Chain60/ProgramMultiSeg.cs | 19 - .../index/snapshot/Chain60/ProgramUseWhen.cs | 27 - .../index/snapshot/Middleware/Startup.cs | 10 - .../index/snapshot/Middleware60/Program.cs | 9 - .../index/snapshot/Program60All3.cs | 50 -- .../index/snapshot/Program60UseExtensions.cs | 19 - .../index/snapshot/Program70All3.cs | 48 -- .../middleware/index/snapshot/StartupAll3.cs | 69 --- .../middleware/rate-limit/samples/readmd.md | 1 - .../middleware/request-response.md | 2 - .../routing/includes/routing3-7.md | 2 - aspnetcore/grpc/aspnetcore.md | 1 - .../grpc/aspnetcore/includes/aspnetcore3.md | 1 - .../grpc/aspnetcore/includes/aspnetcore3_1.md | 1 - .../grpc/aspnetcore/includes/aspnetcore5.md | 1 - .../grpc/aspnetcore/includes/aspnetcore6.md | 1 - .../grpc/aspnetcore/includes/aspnetcore7.md | 1 - aspnetcore/grpc/basics.md | 2 - .../host-and-deploy/proxy-load-balancer.md | 2 +- aspnetcore/includes/code-comments-loc.md | 1 - .../mvc/advanced/custom-model-binding.md | 1 - aspnetcore/mvc/controllers/filters.md | 4 + .../filters/_static/filter-pipeline-3.svg} | 0 aspnetcore/security/authentication/cookie.md | 4 - .../implementation/key-management.md | 2 - .../implementation/key-storage-providers.md | 2 - aspnetcore/signalr/authn-and-authz.md | 2 - 42 files changed, 721 insertions(+), 519 deletions(-) delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain/Startup.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMap.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMapWhen.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMultiSeg.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupUseWhen.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain60/Program.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMap.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMapWhen.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMultiSeg.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramUseWhen.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Middleware/Startup.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Middleware60/Program.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Program60All3.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Program60UseExtensions.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/Program70All3.cs delete mode 100644 aspnetcore/fundamentals/middleware/index/snapshot/StartupAll3.cs delete mode 100644 aspnetcore/fundamentals/middleware/rate-limit/samples/readmd.md delete mode 100644 aspnetcore/includes/code-comments-loc.md rename aspnetcore/{fundamentals/middleware/index/_static/mvc-endpoint.svg => mvc/controllers/filters/_static/filter-pipeline-3.svg} (100%) diff --git a/aspnetcore/blazor/host-and-deploy/app-base-path.md b/aspnetcore/blazor/host-and-deploy/app-base-path.md index 440b9c4557e7..5117cebc7e3a 100644 --- a/aspnetcore/blazor/host-and-deploy/app-base-path.md +++ b/aspnetcore/blazor/host-and-deploy/app-base-path.md @@ -218,7 +218,7 @@ In many hosting scenarios, the relative URL path to the app is the root of the a :::moniker-end > [!NOTE] -> When using (see ), [`app.UseRouting`](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A) must be called after so that the Routing Middleware can observe the modified path before matching routes. Otherwise, routes are matched before the path is rewritten by as described in the [Middleware Ordering](xref:fundamentals/middleware/index#order) and [Routing](xref:fundamentals/routing) articles. +> When using (see ), [`app.UseRouting`](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A) must be called after so that the Routing Middleware can observe the modified path before matching routes. Otherwise, routes are matched before the path is rewritten by as described in the and . Don't prefix links throughout the app with a forward slash. Either avoid the use of a path segment separator or use dot-slash (`./`) relative path notation: diff --git a/aspnetcore/data/ef-rp/update-related-data.md b/aspnetcore/data/ef-rp/update-related-data.md index 7bbb093802c8..8e1ddc463305 100644 --- a/aspnetcore/data/ef-rp/update-related-data.md +++ b/aspnetcore/data/ef-rp/update-related-data.md @@ -46,8 +46,6 @@ Update `Pages/Courses/Create.cshtml.cs` with the following code: [!code-csharp[](intro/samples/cu50/Pages/Courses/Create.cshtml.cs?highlight=7,18,27-41)] -[!INCLUDE[loc comments](~/includes/code-comments-loc.md)] - The preceding code: * Derives from `DepartmentNamePageModel`. @@ -269,8 +267,6 @@ Update `Pages/Courses/Create.cshtml.cs` with the following code: [!code-csharp[](intro/samples/cu30/Pages/Courses/Create.cshtml.cs?highlight=7,18,27-41)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] - The preceding code: * Derives from `DepartmentNamePageModel`. diff --git a/aspnetcore/fundamentals/app-state.md b/aspnetcore/fundamentals/app-state.md index 68e5d0dfaaf4..e4afce074600 100644 --- a/aspnetcore/fundamentals/app-state.md +++ b/aspnetcore/fundamentals/app-state.md @@ -92,7 +92,7 @@ The following code shows how to set up the in-memory session provider with a def The preceding code sets a short timeout to simplify testing. -The order of middleware is important. Call `UseSession` after `UseRouting` and before `MapRazorPages` and `MapDefaultControllerRoute` . See [Middleware Ordering](xref:fundamentals/middleware/index#order). +The order of middleware is important. Call `UseSession` after `UseRouting` and before `MapRazorPages` and `MapDefaultControllerRoute` . See [Middleware Ordering](xref:fundamentals/middleware/index#middleware-order). [HttpContext.Session](xref:Microsoft.AspNetCore.Http.HttpContext.Session) is available after session state is configured. @@ -376,7 +376,7 @@ The following code shows how to set up the in-memory session provider with a def The preceding code sets a short timeout to simplify testing. -The order of middleware is important. Call `UseSession` after `UseRouting` and before `UseEndpoints`. See [Middleware Ordering](xref:fundamentals/middleware/index#order). +The order of middleware is important. Call `UseSession` after `UseRouting` and before `UseEndpoints`. For more information, see . [HttpContext.Session](xref:Microsoft.AspNetCore.Http.HttpContext.Session) is available after session state is configured. diff --git a/aspnetcore/fundamentals/http-requests.md b/aspnetcore/fundamentals/http-requests.md index def559cb6f3c..c5d44e61fecb 100644 --- a/aspnetcore/fundamentals/http-requests.md +++ b/aspnetcore/fundamentals/http-requests.md @@ -890,7 +890,6 @@ Typed clients: A typed client accepts an `HttpClient` parameter in its constructor: :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/GitHub/GitHubService.cs" id="snippet1" highlight="5"::: -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] In the preceding code: diff --git a/aspnetcore/fundamentals/localization/includes/localization35.md b/aspnetcore/fundamentals/localization/includes/localization35.md index ee9737598664..badfa25b2a3e 100644 --- a/aspnetcore/fundamentals/localization/includes/localization35.md +++ b/aspnetcore/fundamentals/localization/includes/localization35.md @@ -255,8 +255,6 @@ The current culture on a request is set in the localization [Middleware](xref:fu [!code-csharp[](~/fundamentals/localization/sample/3.x/Localization/Startup.cs?name=snippet2)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] - `UseRequestLocalization` initializes a `RequestLocalizationOptions` object. On every request the list of `RequestCultureProvider` in the `RequestLocalizationOptions` is enumerated and the first provider that can successfully determine the request culture is used. The default providers come from the `RequestLocalizationOptions` class: 1. `QueryStringRequestCultureProvider` diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 9c13018aadc7..958c0b71b6cd 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -1,13 +1,13 @@ --- title: ASP.NET Core Middleware +ai-usage: ai-assisted author: tdykstra description: Learn about ASP.NET Core middleware and the request pipeline. monikerRange: '>= aspnetcore-3.0' ms.author: tdykstra ms.custom: mvc -ms.date: 06/21/2025 +ms.date: 01/13/2026 uid: fundamentals/middleware/index -ms.ai: assisted --- # ASP.NET Core Middleware @@ -15,8 +15,6 @@ ms.ai: assisted :::moniker range=">= aspnetcore-8.0" -By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Steve Smith](https://ardalis.com/) - 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. @@ -48,13 +46,30 @@ Each delegate can perform operations before and after the next delegate. Excepti The simplest possible ASP.NET Core app sets up a single request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Middleware60/Program.cs)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello world!"); +}); + +app.Run(); +``` Chain multiple request delegates together with . The `next` parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by *not* calling the `next` parameter. You can typically perform actions both before and after the `next` delegate, as the following example demonstrates: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/Program.cs?highlight=4-9)] +```csharp +app.Use(async (context, next) => +{ + // Do work that can write to the Response. + await next.Invoke(); + // Do logging or other work that doesn't write to the Response. +}); +``` -### Short-circuiting the request pipeline +### Short-circuit the request pipeline When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. @@ -72,23 +87,25 @@ For more information, see [Short-circuit middleware after routing](xref:fundamen delegates don't receive a `next` parameter. The first `Run` delegate is always terminal and terminates the pipeline. `Run` is a convention. Some middleware components may expose `Run[Middleware]` methods that run at the end of the pipeline: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/Program.cs?highlight=11-14)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] +```csharp +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from 2nd delegate."); +}); +``` In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. -### Prefer app.Use overload that requires passing the context to next +### Prefer `app.Use` overload that requires passing the context to next -The non-allocating [app.Use](xref:Microsoft.AspNetCore.Builder.IApplicationBuilder.Use%2A) extension method: +The non-allocating extension method: * Requires passing the context to `next`. * Saves two internal per-request allocations that are required when using the other overload. -For more information, see [this GitHub issue](https://github.com/dotnet/aspnetcore/pull/31784). - - +For more information, see [Add new Use middleware extension method (`dotnet/aspnetcore` #31784)](https://github.com/dotnet/aspnetcore/pull/31784). ## Middleware order @@ -114,13 +131,60 @@ The **Endpoint** middleware in the preceding diagram executes the filter pipelin The **Routing** middleware in the preceding diagram is shown following **Static Files**. This is the order that the project templates implement by explicitly calling [app.UseRouting](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A). If you don't call `app.UseRouting`, the **Routing** middleware runs at the beginning of the pipeline by default. For more information, see [Routing](xref:fundamentals/routing). -![ASP.NET Core filter pipeline](~/fundamentals/middleware/index/_static/mvc-endpoint.svg) - The order that middleware components are added in the `Program.cs` file defines the order in which the middleware components are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Program70All3.cs?highlight=19-44)] +```csharp +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using WebMiddleware.Data; + +var builder = WebApplication.CreateBuilder(args); + +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") + ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); +builder.Services.AddControllersWithViews(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +// app.UseCookiePolicy(); + +app.UseRouting(); +// app.UseRateLimiter(); +// app.UseRequestLocalization(); +// app.UseCors(); + +app.UseAuthentication(); +app.UseAuthorization(); +// app.UseSession(); +// app.UseResponseCompression(); +// app.UseResponseCaching(); + +app.MapRazorPages(); +app.MapDefaultControllerRoute(); + +app.Run(); +``` In the preceding code: @@ -210,7 +274,7 @@ app.MapRazorPages(); For information about Single Page Applications, see . -## UseCors and UseStaticFiles order +## `UseCors` and `UseStaticFiles` order The order for calling `UseCors` and `UseStaticFiles` depends on the app. For more information, see [UseCors and UseStaticFiles order](xref:security/cors#uc1) @@ -222,7 +286,37 @@ The order for calling `UseCors` and `UseStaticFiles` depends on the app. For mor extensions are used as a convention for branching the pipeline. `Map` branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMap.cs)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Map("/map1", HandleMapTest1); + +app.Map("/map2", HandleMapTest2); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleMapTest1(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); +} + +static void HandleMapTest2(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 2"); + }); +} +``` The following table shows the requests and responses from `http://localhost:1234` using the preceding code. @@ -250,11 +344,52 @@ app.Map("/level1", level1App => { `Map` can also match multiple segments at once: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMultiSeg.cs?highlight=4)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Map("/map1/seg1", HandleMultiSeg); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleMultiSeg(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); +} +``` branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable `branch`: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMapWhen.cs?highlight=4)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleBranch(IApplicationBuilder app) +{ + app.Run(async context => + { + var branchVer = context.Request.Query["branch"]; + await context.Response.WriteAsync($"Branch used = {branchVer}"); + }); +} +``` The following table shows the requests and responses from `http://localhost:1234` using the previous code: @@ -265,7 +400,35 @@ The following table shows the requests and responses from `http://localhost:1234 also branches the request pipeline based on the result of the given predicate. Unlike with `MapWhen`, this branch is rejoined to the main pipeline if it doesn't contain a terminal middleware: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramUseWhen.cs?highlight=4-5)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.UseWhen(context => context.Request.Query.ContainsKey("branch"), + appBuilder => HandleBranchAndRejoin(appBuilder)); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +void HandleBranchAndRejoin(IApplicationBuilder app) +{ + var logger = app.ApplicationServices.GetRequiredService>(); + + app.Use(async (context, next) => + { + var branchVer = context.Request.Query["branch"]; + logger.LogInformation("Branch used = {branchVer}", branchVer); + + // Do work that doesn't write to the Response. + await next(); + // Do other work that doesn't write to the Response. + }); +} +``` In the preceding example, a response of `Hello from non-Map delegate.` is written for all requests. If the request includes a query string variable `branch`, its value is logged before the main pipeline is rejoined. @@ -307,7 +470,7 @@ ASP.NET Core ships with the following middleware components. The *Order* column ## Additional resources -* [Lifetime and registration options](xref:fundamentals/dependency-injection#lifetime-and-registration-options) contains a complete sample of middleware with *scoped*, *transient*, and *singleton* lifetime services. +* [Lifetime and registration options (includes middleware sample)](xref:fundamentals/dependency-injection#lifetime-and-registration-options) * * * [Configure gRPC-Web in ASP.NET Core](xref:grpc/browser#configure-grpc-web-in-aspnet-core) diff --git a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md index 186939ac04aa..64480c7e08dc 100644 --- a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md +++ b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md @@ -33,11 +33,28 @@ Each delegate can perform operations before and after the next delegate. Excepti The simplest possible ASP.NET Core app sets up a single request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Middleware60/Program.cs)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello world!"); +}); + +app.Run(); +``` Chain multiple request delegates together with . The `next` parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by *not* calling the `next` parameter. You can typically perform actions both before and after the `next` delegate, as the following example demonstrates: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/Program.cs?highlight=4-9)] +```csharp +app.Use(async (context, next) => +{ + // Do work that can write to the Response. + await next.Invoke(); + // Do logging or other work that doesn't write to the Response. +}); +``` When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. @@ -51,8 +68,12 @@ When a delegate doesn't pass a request to the next delegate, it's called *short- delegates don't receive a `next` parameter. The first `Run` delegate is always terminal and terminates the pipeline. `Run` is a convention. Some middleware components may expose `Run[Middleware]` methods that run at the end of the pipeline: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/Program.cs?highlight=11-14)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] +```csharp +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from 2nd delegate."); +}); +``` In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. @@ -85,7 +106,56 @@ The order that middleware components are added in the `Program.cs` file defines The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Program70All3.cs?highlight=19-44)] +```csharp +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using WebMiddleware.Data; + +var builder = WebApplication.CreateBuilder(args); + +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") + ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); +builder.Services.AddControllersWithViews(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +// app.UseCookiePolicy(); + +app.UseRouting(); +// app.UseRateLimiter(); +// app.UseRequestLocalization(); +// app.UseCors(); + +app.UseAuthentication(); +app.UseAuthorization(); +// app.UseSession(); +// app.UseResponseCompression(); +// app.UseResponseCaching(); + +app.MapRazorPages(); +app.MapDefaultControllerRoute(); + +app.Run(); +``` In the preceding code: @@ -187,7 +257,37 @@ The order for calling `UseCors` and `UseStaticFiles` depends on the app. For mor extensions are used as a convention for branching the pipeline. `Map` branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMap.cs)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Map("/map1", HandleMapTest1); + +app.Map("/map2", HandleMapTest2); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleMapTest1(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); +} + +static void HandleMapTest2(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 2"); + }); +} +``` The following table shows the requests and responses from `http://localhost:1234` using the preceding code. @@ -215,11 +315,52 @@ app.Map("/level1", level1App => { `Map` can also match multiple segments at once: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMultiSeg.cs?highlight=4)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Map("/map1/seg1", HandleMultiSeg); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleMultiSeg(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); +} +``` branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable `branch`: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMapWhen.cs?highlight=4)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleBranch(IApplicationBuilder app) +{ + app.Run(async context => + { + var branchVer = context.Request.Query["branch"]; + await context.Response.WriteAsync($"Branch used = {branchVer}"); + }); +} +``` The following table shows the requests and responses from `http://localhost:1234` using the previous code: @@ -230,7 +371,35 @@ The following table shows the requests and responses from `http://localhost:1234 also branches the request pipeline based on the result of the given predicate. Unlike with `MapWhen`, this branch is rejoined to the main pipeline if it doesn't short-circuit or contain a terminal middleware: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramUseWhen.cs?highlight=4-5)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.UseWhen(context => context.Request.Query.ContainsKey("branch"), + appBuilder => HandleBranchAndRejoin(appBuilder)); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +void HandleBranchAndRejoin(IApplicationBuilder app) +{ + var logger = app.ApplicationServices.GetRequiredService>(); + + app.Use(async (context, next) => + { + var branchVer = context.Request.Query["branch"]; + logger.LogInformation("Branch used = {branchVer}", branchVer); + + // Do work that doesn't write to the Response. + await next(); + // Do other work that doesn't write to the Response. + }); +} +``` In the preceding example, a response of `Hello from non-Map delegate.` is written for all requests. If the request includes a query string variable `branch`, its value is logged before the main pipeline is rejoined. @@ -311,11 +480,28 @@ Each delegate can perform operations before and after the next delegate. Excepti The simplest possible ASP.NET Core app sets up a single request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Middleware60/Program.cs)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello world!"); +}); + +app.Run(); +``` Chain multiple request delegates together with . The `next` parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by *not* calling the `next` parameter. You can typically perform actions both before and after the `next` delegate, as the following example demonstrates: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/Program.cs?highlight=4-9)] +```csharp +app.Use(async (context, next) => +{ + // Do work that can write to the Response. + await next.Invoke(); + // Do logging or other work that doesn't write to the Response. +}); +``` When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. @@ -329,8 +515,12 @@ When a delegate doesn't pass a request to the next delegate, it's called *short- delegates don't receive a `next` parameter. The first `Run` delegate is always terminal and terminates the pipeline. `Run` is a convention. Some middleware components may expose `Run[Middleware]` methods that run at the end of the pipeline: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/Program.cs?highlight=11-14)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] +```csharp +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from 2nd delegate."); +}); +``` In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. @@ -363,7 +553,58 @@ The order that middleware components are added in the `Program.cs` file defines The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Program60All3.cs?highlight=19-43)] +```csharp +using IndividualAccountsExample.Data; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +// app.UseCookiePolicy(); + +app.UseRouting(); +// app.UseRequestLocalization(); +// app.UseCors(); + +app.UseAuthentication(); +app.UseAuthorization(); +// app.UseSession(); +// app.UseResponseCompression(); +// app.UseResponseCaching(); + +app.MapRazorPages(); +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + +app.Run(); +``` In the preceding code: @@ -464,7 +705,37 @@ The order for calling `UseCors` and `UseStaticFiles` depends on the app. For mor extensions are used as a convention for branching the pipeline. `Map` branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMap.cs)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Map("/map1", HandleMapTest1); + +app.Map("/map2", HandleMapTest2); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleMapTest1(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); +} + +static void HandleMapTest2(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 2"); + }); +} +``` The following table shows the requests and responses from `http://localhost:1234` using the preceding code. @@ -492,11 +763,52 @@ app.Map("/level1", level1App => { `Map` can also match multiple segments at once: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMultiSeg.cs?highlight=4)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Map("/map1/seg1", HandleMultiSeg); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleMultiSeg(IApplicationBuilder app) +{ + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); +} +``` branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable `branch`: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramMapWhen.cs?highlight=4)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +static void HandleBranch(IApplicationBuilder app) +{ + app.Run(async context => + { + var branchVer = context.Request.Query["branch"]; + await context.Response.WriteAsync($"Branch used = {branchVer}"); + }); +} +``` The following table shows the requests and responses from `http://localhost:1234` using the previous code: @@ -507,7 +819,35 @@ The following table shows the requests and responses from `http://localhost:1234 also branches the request pipeline based on the result of the given predicate. Unlike with `MapWhen`, this branch is rejoined to the main pipeline if it doesn't short-circuit or contain a terminal middleware: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain60/ProgramUseWhen.cs?highlight=4-5)] +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.UseWhen(context => context.Request.Query.ContainsKey("branch"), + appBuilder => HandleBranchAndRejoin(appBuilder)); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from non-Map delegate."); +}); + +app.Run(); + +void HandleBranchAndRejoin(IApplicationBuilder app) +{ + var logger = app.ApplicationServices.GetRequiredService>(); + + app.Use(async (context, next) => + { + var branchVer = context.Request.Query["branch"]; + logger.LogInformation("Branch used = {branchVer}", branchVer); + + // Do work that doesn't write to the Response. + await next(); + // Do other work that doesn't write to the Response. + }); +} +``` In the preceding example, a response of `Hello from non-Map delegate.` is written for all requests. If the request includes a query string variable `branch`, its value is logged before the main pipeline is rejoined. @@ -583,11 +923,29 @@ Each delegate can perform operations before and after the next delegate. Excepti The simplest possible ASP.NET Core app sets up a single request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Middleware/Startup.cs)] +```csharp +public class Startup +{ + public void Configure(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Hello, World!"); + }); + } +} +``` Chain multiple request delegates together with . The `next` parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by *not* calling the *next* parameter. You can typically perform actions both before and after the next delegate, as the following example demonstrates: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain/Startup.cs?highlight=5-10)] +```csharp +app.Use(async (context, next) => +{ + // Do work that doesn't write to the Response. + await next.Invoke(); + // Do logging or other work that doesn't write to the Response. +}); +``` When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. @@ -601,13 +959,15 @@ When a delegate doesn't pass a request to the next delegate, it's called *short- delegates don't receive a `next` parameter. The first `Run` delegate is always terminal and terminates the pipeline. `Run` is a convention. Some middleware components may expose `Run[Middleware]` methods that run at the end of the pipeline: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain/Startup.cs?highlight=12-15)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] +```csharp +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from 2nd delegate."); +}); +``` In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. - - ## Middleware order The following diagram shows the complete request processing pipeline for ASP.NET Core MVC and Razor Pages apps. You can see how, in a typical app, existing middlewares are ordered and where custom middlewares are added. You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios. @@ -622,7 +982,43 @@ The order that middleware components are added in the `Startup.Configure` method The following `Startup.Configure` method adds security-related middleware components in the typical recommended order: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/StartupAll3.cs?name=snippet)] +```csharp +public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +{ + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseDatabaseErrorPage(); + } + else + { + app.UseExceptionHandler("/Error"); + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseStaticFiles(); + // app.UseCookiePolicy(); + + app.UseRouting(); + // app.UseRequestLocalization(); + // app.UseCors(); + + app.UseAuthentication(); + app.UseAuthorization(); + // app.UseSession(); + // app.UseResponseCompression(); + // app.UseResponseCaching(); + + app.UseEndpoints(endpoints => + { + endpoints.MapRazorPages(); + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + }); +} +``` In the preceding code: @@ -738,7 +1134,38 @@ For more details on SPAs, see the guides for the [React](xref:spa/react) and [An extensions are used as a convention for branching the pipeline. `Map` branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain/StartupMap.cs)] +```csharp +public class Startup +{ + private static void HandleMapTest1(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); + } + + private static void HandleMapTest2(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 2"); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.Map("/map1", HandleMapTest1); + + app.Map("/map2", HandleMapTest2); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from non-Map delegate."); + }); + } +} +``` The following table shows the requests and responses from `http://localhost:1234` using the previous code. @@ -766,11 +1193,55 @@ app.Map("/level1", level1App => { `Map` can also match multiple segments at once: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain/StartupMultiSeg.cs?highlight=13)] +```csharp +public class Startup +{ + private static void HandleMultiSeg(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Map multiple segments."); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.Map("/map1/seg1", HandleMultiSeg); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from non-Map delegate."); + }); + } +} +``` branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable `branch`: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain/StartupMapWhen.cs?highlight=14-15)] +```csharp +public class Startup +{ + private static void HandleBranch(IApplicationBuilder app) + { + app.Run(async context => + { + var branchVer = context.Request.Query["branch"]; + await context.Response.WriteAsync($"Branch used = {branchVer}"); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.MapWhen(context => context.Request.Query.ContainsKey("branch"), + HandleBranch); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from non-Map delegate."); + }); + } +} +``` The following table shows the requests and responses from `http://localhost:1234` using the previous code: @@ -781,7 +1252,34 @@ The following table shows the requests and responses from `http://localhost:1234 also branches the request pipeline based on the result of the given predicate. Unlike with `MapWhen`, this branch is rejoined to the main pipeline if it doesn't short-circuit or contain a terminal middleware: -[!code-csharp[](~/fundamentals/middleware/index/snapshot/Chain/StartupUseWhen.cs?highlight=18-19)] +```csharp +public class Startup +{ + private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger logger) + { + app.Use(async (context, next) => + { + var branchVer = context.Request.Query["branch"]; + logger.LogInformation("Branch used = {branchVer}", branchVer); + + // Do work that doesn't write to the Response. + await next(); + // Do other work that doesn't write to the Response. + }); + } + + public void Configure(IApplicationBuilder app, ILogger logger) + { + app.UseWhen(context => context.Request.Query.ContainsKey("branch"), + appBuilder => HandleBranchAndRejoin(appBuilder, logger)); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from main pipeline."); + }); + } +} +``` In the preceding example, a response of "Hello from main pipeline." is written for all requests. If the request includes a query string variable `branch`, its value is logged before the main pipeline is rejoined. diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/Startup.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain/Startup.cs deleted file mode 100644 index 7daa89a4db4c..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/Startup.cs +++ /dev/null @@ -1,17 +0,0 @@ -public class Startup -{ - public void Configure(IApplicationBuilder app) - { - app.Use(async (context, next) => - { - // Do work that doesn't write to the Response. - await next.Invoke(); - // Do logging or other work that doesn't write to the Response. - }); - - app.Run(async context => - { - await context.Response.WriteAsync("Hello from 2nd delegate."); - }); - } -} diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMap.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMap.cs deleted file mode 100644 index 57cab9e3eb73..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMap.cs +++ /dev/null @@ -1,30 +0,0 @@ -public class Startup -{ - private static void HandleMapTest1(IApplicationBuilder app) - { - app.Run(async context => - { - await context.Response.WriteAsync("Map Test 1"); - }); - } - - private static void HandleMapTest2(IApplicationBuilder app) - { - app.Run(async context => - { - await context.Response.WriteAsync("Map Test 2"); - }); - } - - public void Configure(IApplicationBuilder app) - { - app.Map("/map1", HandleMapTest1); - - app.Map("/map2", HandleMapTest2); - - app.Run(async context => - { - await context.Response.WriteAsync("Hello from non-Map delegate."); - }); - } -} diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMapWhen.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMapWhen.cs deleted file mode 100644 index f6e9b276177f..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMapWhen.cs +++ /dev/null @@ -1,22 +0,0 @@ -public class Startup -{ - private static void HandleBranch(IApplicationBuilder app) - { - app.Run(async context => - { - var branchVer = context.Request.Query["branch"]; - await context.Response.WriteAsync($"Branch used = {branchVer}"); - }); - } - - public void Configure(IApplicationBuilder app) - { - app.MapWhen(context => context.Request.Query.ContainsKey("branch"), - HandleBranch); - - app.Run(async context => - { - await context.Response.WriteAsync("Hello from non-Map delegate."); - }); - } -} diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMultiSeg.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMultiSeg.cs deleted file mode 100644 index 0587d1d4537f..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupMultiSeg.cs +++ /dev/null @@ -1,20 +0,0 @@ -public class Startup -{ - private static void HandleMultiSeg(IApplicationBuilder app) - { - app.Run(async context => - { - await context.Response.WriteAsync("Map multiple segments."); - }); - } - - public void Configure(IApplicationBuilder app) - { - app.Map("/map1/seg1", HandleMultiSeg); - - app.Run(async context => - { - await context.Response.WriteAsync("Hello from non-Map delegate."); - }); - } -} diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupUseWhen.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupUseWhen.cs deleted file mode 100644 index 6366f79414f5..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain/StartupUseWhen.cs +++ /dev/null @@ -1,26 +0,0 @@ -public class Startup -{ - private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger logger) - { - app.Use(async (context, next) => - { - var branchVer = context.Request.Query["branch"]; - logger.LogInformation("Branch used = {branchVer}", branchVer); - - // Do work that doesn't write to the Response. - await next(); - // Do other work that doesn't write to the Response. - }); - } - - public void Configure(IApplicationBuilder app, ILogger logger) - { - app.UseWhen(context => context.Request.Query.ContainsKey("branch"), - appBuilder => HandleBranchAndRejoin(appBuilder, logger)); - - app.Run(async context => - { - await context.Response.WriteAsync("Hello from main pipeline."); - }); - } -} diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/Program.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/Program.cs deleted file mode 100644 index 068f924af16a..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/Program.cs +++ /dev/null @@ -1,16 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); - -app.Use(async (context, next) => -{ - // Do work that can write to the Response. - await next.Invoke(); - // Do logging or other work that doesn't write to the Response. -}); - -app.Run(async context => -{ - await context.Response.WriteAsync("Hello from 2nd delegate."); -}); - -app.Run(); diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMap.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMap.cs deleted file mode 100644 index e478e8a53f08..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMap.cs +++ /dev/null @@ -1,29 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); - -app.Map("/map1", HandleMapTest1); - -app.Map("/map2", HandleMapTest2); - -app.Run(async context => -{ - await context.Response.WriteAsync("Hello from non-Map delegate."); -}); - -app.Run(); - -static void HandleMapTest1(IApplicationBuilder app) -{ - app.Run(async context => - { - await context.Response.WriteAsync("Map Test 1"); - }); -} - -static void HandleMapTest2(IApplicationBuilder app) -{ - app.Run(async context => - { - await context.Response.WriteAsync("Map Test 2"); - }); -} \ No newline at end of file diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMapWhen.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMapWhen.cs deleted file mode 100644 index ba98e16e2f03..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMapWhen.cs +++ /dev/null @@ -1,20 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); - -app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch); - -app.Run(async context => -{ - await context.Response.WriteAsync("Hello from non-Map delegate."); -}); - -app.Run(); - -static void HandleBranch(IApplicationBuilder app) -{ - app.Run(async context => - { - var branchVer = context.Request.Query["branch"]; - await context.Response.WriteAsync($"Branch used = {branchVer}"); - }); -} \ No newline at end of file diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMultiSeg.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMultiSeg.cs deleted file mode 100644 index 4f3c1f1ba44e..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramMultiSeg.cs +++ /dev/null @@ -1,19 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); - -app.Map("/map1/seg1", HandleMultiSeg); - -app.Run(async context => -{ - await context.Response.WriteAsync("Hello from non-Map delegate."); -}); - -app.Run(); - -static void HandleMultiSeg(IApplicationBuilder app) -{ - app.Run(async context => - { - await context.Response.WriteAsync("Map Test 1"); - }); -} diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramUseWhen.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramUseWhen.cs deleted file mode 100644 index a15237e0f48f..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Chain60/ProgramUseWhen.cs +++ /dev/null @@ -1,27 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); - -app.UseWhen(context => context.Request.Query.ContainsKey("branch"), - appBuilder => HandleBranchAndRejoin(appBuilder)); - -app.Run(async context => -{ - await context.Response.WriteAsync("Hello from non-Map delegate."); -}); - -app.Run(); - -void HandleBranchAndRejoin(IApplicationBuilder app) -{ - var logger = app.ApplicationServices.GetRequiredService>(); - - app.Use(async (context, next) => - { - var branchVer = context.Request.Query["branch"]; - logger.LogInformation("Branch used = {branchVer}", branchVer); - - // Do work that doesn't write to the Response. - await next(); - // Do other work that doesn't write to the Response. - }); -} \ No newline at end of file diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Middleware/Startup.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Middleware/Startup.cs deleted file mode 100644 index d93aab1c5353..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Middleware/Startup.cs +++ /dev/null @@ -1,10 +0,0 @@ -public class Startup -{ - public void Configure(IApplicationBuilder app) - { - app.Run(async context => - { - await context.Response.WriteAsync("Hello, World!"); - }); - } -} diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Middleware60/Program.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Middleware60/Program.cs deleted file mode 100644 index a13ee4df070c..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Middleware60/Program.cs +++ /dev/null @@ -1,9 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); - -app.Run(async context => -{ - await context.Response.WriteAsync("Hello world!"); -}); - -app.Run(); \ No newline at end of file diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Program60All3.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Program60All3.cs deleted file mode 100644 index 02b1cb378927..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Program60All3.cs +++ /dev/null @@ -1,50 +0,0 @@ -using IndividualAccountsExample.Data; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; - -var builder = WebApplication.CreateBuilder(args); - -// Add services to the container. -var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); -builder.Services.AddDbContext(options => - options.UseSqlServer(connectionString)); -builder.Services.AddDatabaseDeveloperPageExceptionFilter(); - -builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) - .AddEntityFrameworkStores(); -builder.Services.AddRazorPages(); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.UseMigrationsEndPoint(); -} -else -{ - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); -} - -app.UseHttpsRedirection(); -app.UseStaticFiles(); -// app.UseCookiePolicy(); - -app.UseRouting(); -// app.UseRequestLocalization(); -// app.UseCors(); - -app.UseAuthentication(); -app.UseAuthorization(); -// app.UseSession(); -// app.UseResponseCompression(); -// app.UseResponseCaching(); - -app.MapRazorPages(); -app.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - -app.Run(); diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Program60UseExtensions.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Program60UseExtensions.cs deleted file mode 100644 index 315a7f4cc5e9..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Program60UseExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); - -/* - 1. next is type of RequestDelegate which requires passing the HttpContext - 2. Use this for performance benefits - 3. Saves two per request allocations over the previous Use extension -*/ - -#region snippet1 -app.Use(async (context, next) => -{ - // Do work that doesn't write to the Response. - await next.Invoke(context); - // Do logging or other work that doesn't write to the Response. -}); -#endregion - -app.Run(); diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/Program70All3.cs b/aspnetcore/fundamentals/middleware/index/snapshot/Program70All3.cs deleted file mode 100644 index 5dcfcc7e033e..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/Program70All3.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using WebMiddleware.Data; - -var builder = WebApplication.CreateBuilder(args); - -var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") - ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); -builder.Services.AddDbContext(options => - options.UseSqlServer(connectionString)); -builder.Services.AddDatabaseDeveloperPageExceptionFilter(); - -builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) - .AddEntityFrameworkStores(); -builder.Services.AddRazorPages(); -builder.Services.AddControllersWithViews(); - -var app = builder.Build(); - -if (app.Environment.IsDevelopment()) -{ - app.UseMigrationsEndPoint(); -} -else -{ - app.UseExceptionHandler("/Error"); - app.UseHsts(); -} - -app.UseHttpsRedirection(); -app.UseStaticFiles(); -// app.UseCookiePolicy(); - -app.UseRouting(); -// app.UseRateLimiter(); -// app.UseRequestLocalization(); -// app.UseCors(); - -app.UseAuthentication(); -app.UseAuthorization(); -// app.UseSession(); -// app.UseResponseCompression(); -// app.UseResponseCaching(); - -app.MapRazorPages(); -app.MapDefaultControllerRoute(); - -app.Run(); diff --git a/aspnetcore/fundamentals/middleware/index/snapshot/StartupAll3.cs b/aspnetcore/fundamentals/middleware/index/snapshot/StartupAll3.cs deleted file mode 100644 index 43e9260575ca..000000000000 --- a/aspnetcore/fundamentals/middleware/index/snapshot/StartupAll3.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using WebApplication51.Data; - -namespace WebApplication51 -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - public void ConfigureServices(IServiceCollection services) - { - services.AddDbContext(options => - options.UseSqlServer( - Configuration.GetConnectionString("DefaultConnection"))); - services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) - .AddEntityFrameworkStores(); - services.AddRazorPages(); - } - - #region snippet - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseDatabaseErrorPage(); - } - else - { - app.UseExceptionHandler("/Error"); - app.UseHsts(); - } - - app.UseHttpsRedirection(); - app.UseStaticFiles(); - // app.UseCookiePolicy(); - - app.UseRouting(); - // app.UseRequestLocalization(); - // app.UseCors(); - - app.UseAuthentication(); - app.UseAuthorization(); - // app.UseSession(); - // app.UseResponseCompression(); - // app.UseResponseCaching(); - - app.UseEndpoints(endpoints => - { - endpoints.MapRazorPages(); - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - } - #endregion - } -} diff --git a/aspnetcore/fundamentals/middleware/rate-limit/samples/readmd.md b/aspnetcore/fundamentals/middleware/rate-limit/samples/readmd.md deleted file mode 100644 index 87e5a8686e0a..000000000000 --- a/aspnetcore/fundamentals/middleware/rate-limit/samples/readmd.md +++ /dev/null @@ -1 +0,0 @@ -Delete this file after adding rate limiting sample code. diff --git a/aspnetcore/fundamentals/middleware/request-response.md b/aspnetcore/fundamentals/middleware/request-response.md index 975eff2e17d8..c6c47a45512b 100644 --- a/aspnetcore/fundamentals/middleware/request-response.md +++ b/aspnetcore/fundamentals/middleware/request-response.md @@ -43,8 +43,6 @@ Suppose the goal is to create a middleware that reads the entire request body as [!code-csharp[](request-response/samples/3.x/RequestResponseSample/Startup.cs?name=GetListOfStringsFromStream)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] - This code works, but there are some issues: * Before appending to the `StringBuilder`, the example creates another string (`encodedString`) that is thrown away immediately. This process occurs for all bytes in the stream, so the result is extra memory allocation the size of the entire request body. diff --git a/aspnetcore/fundamentals/routing/includes/routing3-7.md b/aspnetcore/fundamentals/routing/includes/routing3-7.md index 5cbb1a201253..f509cd6f7929 100644 --- a/aspnetcore/fundamentals/routing/includes/routing3-7.md +++ b/aspnetcore/fundamentals/routing/includes/routing3-7.md @@ -2103,8 +2103,6 @@ The following example shows routing with [health checks](xref:host-and-deploy/he :::code language="csharp" source="~/fundamentals/routing/samples/3.x/RoutingSample/AuthorizationStartup.cs" id="snippet"::: -[!INCLUDE[request localized comments](~/includes/code-comments-loc.md)] - The preceding example demonstrates how: * The authorization middleware can be used with routing. diff --git a/aspnetcore/grpc/aspnetcore.md b/aspnetcore/grpc/aspnetcore.md index c7a57280335e..2d7f42f9fca9 100644 --- a/aspnetcore/grpc/aspnetcore.md +++ b/aspnetcore/grpc/aspnetcore.md @@ -52,7 +52,6 @@ In `Program.cs`: * Each gRPC service is added to the routing pipeline through the `MapGrpcService` method. [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample6/GrpcGreeter/Program.cs?highlight=9,14)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ASP.NET Core middleware and features share the routing pipeline, therefore an app can be configured to serve additional request handlers. The additional request handlers, such as MVC controllers, work in parallel with the configured gRPC services. diff --git a/aspnetcore/grpc/aspnetcore/includes/aspnetcore3.md b/aspnetcore/grpc/aspnetcore/includes/aspnetcore3.md index 3add546da0f5..af559c584412 100644 --- a/aspnetcore/grpc/aspnetcore/includes/aspnetcore3.md +++ b/aspnetcore/grpc/aspnetcore/includes/aspnetcore3.md @@ -43,7 +43,6 @@ In `Startup.cs`: * Each gRPC service is added to the routing pipeline through the `MapGrpcService` method. [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample3-5/GrpcGreeter/Startup.cs?name=snippet&highlight=7,24)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ASP.NET Core middleware and features share the routing pipeline, therefore an app can be configured to serve additional request handlers. The additional request handlers, such as MVC controllers, work in parallel with the configured gRPC services. diff --git a/aspnetcore/grpc/aspnetcore/includes/aspnetcore3_1.md b/aspnetcore/grpc/aspnetcore/includes/aspnetcore3_1.md index 8f28feacf61c..c70f0e4e06c4 100644 --- a/aspnetcore/grpc/aspnetcore/includes/aspnetcore3_1.md +++ b/aspnetcore/grpc/aspnetcore/includes/aspnetcore3_1.md @@ -43,7 +43,6 @@ In `Startup.cs`: * Each gRPC service is added to the routing pipeline through the `MapGrpcService` method. [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample3-5/GrpcGreeter/Startup.cs?name=snippet&highlight=7,24)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ASP.NET Core middleware and features share the routing pipeline, therefore an app can be configured to serve additional request handlers. The additional request handlers, such as MVC controllers, work in parallel with the configured gRPC services. diff --git a/aspnetcore/grpc/aspnetcore/includes/aspnetcore5.md b/aspnetcore/grpc/aspnetcore/includes/aspnetcore5.md index b71f6874baa4..3248c68dda26 100644 --- a/aspnetcore/grpc/aspnetcore/includes/aspnetcore5.md +++ b/aspnetcore/grpc/aspnetcore/includes/aspnetcore5.md @@ -43,7 +43,6 @@ In `Startup.cs`: * Each gRPC service is added to the routing pipeline through the `MapGrpcService` method. [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample3-5/GrpcGreeter/Startup.cs?name=snippet&highlight=7,24)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ASP.NET Core middleware and features share the routing pipeline, therefore an app can be configured to serve additional request handlers. The additional request handlers, such as MVC controllers, work in parallel with the configured gRPC services. diff --git a/aspnetcore/grpc/aspnetcore/includes/aspnetcore6.md b/aspnetcore/grpc/aspnetcore/includes/aspnetcore6.md index cb9ac776838a..fa3e4b73d0e7 100644 --- a/aspnetcore/grpc/aspnetcore/includes/aspnetcore6.md +++ b/aspnetcore/grpc/aspnetcore/includes/aspnetcore6.md @@ -43,7 +43,6 @@ In `Program.cs`: * Each gRPC service is added to the routing pipeline through the `MapGrpcService` method. [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample6/GrpcGreeter/Program.cs?highlight=9,14)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ASP.NET Core middleware and features share the routing pipeline, therefore an app can be configured to serve additional request handlers. The additional request handlers, such as MVC controllers, work in parallel with the configured gRPC services. diff --git a/aspnetcore/grpc/aspnetcore/includes/aspnetcore7.md b/aspnetcore/grpc/aspnetcore/includes/aspnetcore7.md index 2fc276a7492c..3413d7b1a989 100644 --- a/aspnetcore/grpc/aspnetcore/includes/aspnetcore7.md +++ b/aspnetcore/grpc/aspnetcore/includes/aspnetcore7.md @@ -43,7 +43,6 @@ In `Program.cs`: * Each gRPC service is added to the routing pipeline through the `MapGrpcService` method. [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample6/GrpcGreeter/Program.cs?highlight=9,14)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ASP.NET Core middleware and features share the routing pipeline, therefore an app can be configured to serve additional request handlers. The additional request handlers, such as MVC controllers, work in parallel with the configured gRPC services. diff --git a/aspnetcore/grpc/basics.md b/aspnetcore/grpc/basics.md index b2ac423c1840..34d85ff7ae86 100644 --- a/aspnetcore/grpc/basics.md +++ b/aspnetcore/grpc/basics.md @@ -30,7 +30,6 @@ For example, consider the *greet.proto* file used in [Get started with gRPC serv * `SayHello` sends a `HelloRequest` message and receives a `HelloReply` message: [!code-protobuf[](~/tutorials/grpc/grpc-start/sample/sample6/GrpcGreeter/Protos/greet.proto)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ## Add a `.proto` file to a C\# app @@ -106,7 +105,6 @@ For example, consider the *greet.proto* file used in [Get started with gRPC serv * `SayHello` sends a `HelloRequest` message and receives a `HelloReply` message: [!code-protobuf[](~/tutorials/grpc/grpc-start/sample/sample3-5/GrpcGreeter/Protos/greet.proto)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] ## Add a `.proto` file to a C\# app diff --git a/aspnetcore/host-and-deploy/proxy-load-balancer.md b/aspnetcore/host-and-deploy/proxy-load-balancer.md index 18831d273c80..f09f9a9559af 100644 --- a/aspnetcore/host-and-deploy/proxy-load-balancer.md +++ b/aspnetcore/host-and-deploy/proxy-load-balancer.md @@ -139,7 +139,7 @@ app.UseRouting(); ``` > [!NOTE] -> When using (see ), [`app.UseRouting`](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A) must be called after `UsePathBase` so that the routing middleware can observe the modified path before matching routes. Otherwise, routes are matched before the path is rewritten by `UsePathBase` as described in the [Middleware Ordering](xref:fundamentals/middleware/index#order) and [Routing](xref:fundamentals/routing) articles. +> When using (see ), [`app.UseRouting`](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A) must be called after `UsePathBase` so that the routing middleware can observe the modified path before matching routes. Otherwise, routes are matched before the path is rewritten by `UsePathBase` as described in and . The original path and path base are reapplied when the middleware is called again in reverse. For more information on middleware order processing, see . diff --git a/aspnetcore/includes/code-comments-loc.md b/aspnetcore/includes/code-comments-loc.md deleted file mode 100644 index f65eeb64275e..000000000000 --- a/aspnetcore/includes/code-comments-loc.md +++ /dev/null @@ -1 +0,0 @@ -If you would like to see code comments translated to languages other than English, let us know in [this GitHub discussion issue](https://github.com/MicrosoftDocs/feedback/issues/2515). \ No newline at end of file diff --git a/aspnetcore/mvc/advanced/custom-model-binding.md b/aspnetcore/mvc/advanced/custom-model-binding.md index 092b9e44b9a7..fe3de3cf6ec6 100644 --- a/aspnetcore/mvc/advanced/custom-model-binding.md +++ b/aspnetcore/mvc/advanced/custom-model-binding.md @@ -58,7 +58,6 @@ When creating your own custom model binder, you can implement your own `IModelBi The following example shows how to use `ByteArrayModelBinder` to convert a base64-encoded string to a `byte[]` and save the result to a file: [!code-csharp[](custom-model-binding/samples/3.x/CustomModelBindingSample/Controllers/ImageController.cs?name=snippet_Post)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] You can POST a base64-encoded string to the previous api method using a tool like [curl](https://curl.haxx.se/). diff --git a/aspnetcore/mvc/controllers/filters.md b/aspnetcore/mvc/controllers/filters.md index 42b8163db2fd..e5e14a1783b4 100644 --- a/aspnetcore/mvc/controllers/filters.md +++ b/aspnetcore/mvc/controllers/filters.md @@ -34,6 +34,10 @@ Filters run within the *ASP.NET Core action invocation pipeline*, sometimes refe :::image source="~/mvc/controllers/filters/_static/filter-pipeline-1.png" alt-text="The request is processed through Other Middleware, Routing Middleware, Action Selection, and the Action Invocation Pipeline. The request processing continues back through Action Selection, Routing Middleware, and various Other Middleware before becoming a response sent to the client."::: +The following diagram shows the filter pipeline execution order for MVC and Razor Pages: + +![ASP.NET Core filter pipeline](~/mvc/controllers/filters/_static/filter-pipeline-3.svg) + ### Filter types Each filter type is executed at a different stage in the filter pipeline: diff --git a/aspnetcore/fundamentals/middleware/index/_static/mvc-endpoint.svg b/aspnetcore/mvc/controllers/filters/_static/filter-pipeline-3.svg similarity index 100% rename from aspnetcore/fundamentals/middleware/index/_static/mvc-endpoint.svg rename to aspnetcore/mvc/controllers/filters/_static/filter-pipeline-3.svg diff --git a/aspnetcore/security/authentication/cookie.md b/aspnetcore/security/authentication/cookie.md index 909083f8677c..435924dd7770 100644 --- a/aspnetcore/security/authentication/cookie.md +++ b/aspnetcore/security/authentication/cookie.md @@ -73,8 +73,6 @@ Create a with any required is only used on a few specific paths by default, for example, the login path and logout paths. For more information see the [CookieAuthenticationHandler source](https://github.com/dotnet/aspnetcore/blob/f2e6e6ff334176540ef0b3291122e359c2106d1a/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs#L334). @@ -243,8 +241,6 @@ Create a with any required is only used on a few specific paths by default, for example, the login path and logout paths. For more information see the [CookieAuthenticationHandler source](https://github.com/dotnet/aspnetcore/blob/f2e6e6ff334176540ef0b3291122e359c2106d1a/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs#L334). diff --git a/aspnetcore/security/data-protection/implementation/key-management.md b/aspnetcore/security/data-protection/implementation/key-management.md index c399296bac5b..6a4e09ad30f0 100644 --- a/aspnetcore/security/data-protection/implementation/key-management.md +++ b/aspnetcore/security/data-protection/implementation/key-management.md @@ -70,8 +70,6 @@ The sample below demonstrates using the `IKeyManager` interface to inspect and m [!code-csharp[](key-management/samples/key-management.cs)] -[!INCLUDE[about the series](~/includes/code-comments-loc.md)] - ## Key storage The data protection system has a heuristic whereby it attempts to deduce an appropriate key storage location and encryption-at-rest mechanism automatically. The key persistence mechanism is also configurable by the app developer. The following documents discuss the in-box implementations of these mechanisms: diff --git a/aspnetcore/security/data-protection/implementation/key-storage-providers.md b/aspnetcore/security/data-protection/implementation/key-storage-providers.md index 29cf2b52abc1..e29a90cd0d54 100644 --- a/aspnetcore/security/data-protection/implementation/key-storage-providers.md +++ b/aspnetcore/security/data-protection/implementation/key-storage-providers.md @@ -316,8 +316,6 @@ To configure the EF Core provider, call the and implement : [!code-csharp[Main](key-storage-providers/sample/MyKeysContext.cs)] diff --git a/aspnetcore/signalr/authn-and-authz.md b/aspnetcore/signalr/authn-and-authz.md index e54523729aef..e219c1f5decd 100644 --- a/aspnetcore/signalr/authn-and-authz.md +++ b/aspnetcore/signalr/authn-and-authz.md @@ -276,8 +276,6 @@ On the server, bearer token authentication is configured using the [JWT Bearer m [!code-csharp[Configure Server to accept access token from Query String](authn-and-authz/sample/Startup.cs?name=snippet)] -[!INCLUDE[request localized comments](~/includes/code-comments-loc.md)] - > [!NOTE] > The query string is used on browsers when connecting with WebSockets and Server-Sent Events due to browser API limitations. When using HTTPS, query string values are secured by the TLS connection. However, many servers log query string values. For more information, see [Security considerations in ASP.NET Core SignalR](xref:signalr/security). SignalR uses headers to transmit tokens in environments which support them (such as the .NET and Java clients). From bece66dbe32568fab3fc5c959707a5c8131f5235 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:47:18 -0500 Subject: [PATCH 02/16] Updates --- aspnetcore/fundamentals/middleware/index/includes/index3-7.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md index 64480c7e08dc..fde8d45dab2e 100644 --- a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md +++ b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md @@ -100,8 +100,6 @@ The **Endpoint** middleware in the preceding diagram executes the filter pipelin The **Routing** middleware in the preceding diagram is shown following **Static Files**. This is the order that the project templates implement by explicitly calling [app.UseRouting](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A). If you don't call `app.UseRouting`, the **Routing** middleware runs at the beginning of the pipeline by default. For more information, see [Routing](xref:fundamentals/routing). -![ASP.NET Core filter pipeline](~/fundamentals/middleware/index/_static/mvc-endpoint.svg) - The order that middleware components are added in the `Program.cs` file defines the order in which the middleware components are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: From dc1e4f1f2db761c13deacb4a1f065878c4a36e0e Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:10:46 -0500 Subject: [PATCH 03/16] Updates --- aspnetcore/fundamentals/middleware/index/includes/index3-7.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md index fde8d45dab2e..0a4eb118614b 100644 --- a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md +++ b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md @@ -545,8 +545,6 @@ The **Endpoint** middleware in the preceding diagram executes the filter pipelin The **Routing** middleware in the preceding diagram is shown following **Static Files**. This is the order that the project templates implement by explicitly calling [app.UseRouting](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A). If you don't call `app.UseRouting`, the **Routing** middleware runs at the beginning of the pipeline by default. For more information, see [Routing](xref:fundamentals/routing). -![ASP.NET Core filter pipeline](~/fundamentals/middleware/index/_static/mvc-endpoint.svg) - The order that middleware components are added in the `Program.cs` file defines the order in which the middleware components are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: @@ -974,8 +972,6 @@ The following diagram shows the complete request processing pipeline for ASP.NET The **Endpoint** middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. -![ASP.NET Core filter pipeline](~/fundamentals/middleware/index/_static/mvc-endpoint.svg) - 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 order is **critical** for security, performance, and functionality. The following `Startup.Configure` method adds security-related middleware components in the typical recommended order: From 978709c6d06c7f8818914ef7b6cfa24c75204645 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:55:14 -0500 Subject: [PATCH 04/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 302 ++++++++++-------- .../middleware/index/includes/index3-7.md | 16 +- aspnetcore/host-and-deploy/linux-nginx.md | 2 +- .../linux-nginx/includes/linux-nginx5.md | 6 +- .../host-and-deploy/proxy-load-balancer.md | 2 - aspnetcore/includes/ForwardedHeaders.md | 1 - 6 files changed, 180 insertions(+), 149 deletions(-) delete mode 100644 aspnetcore/includes/ForwardedHeaders.md diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 958c0b71b6cd..6b08a5e09b74 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -6,7 +6,7 @@ description: Learn about ASP.NET Core middleware and the request pipeline. monikerRange: '>= aspnetcore-3.0' ms.author: tdykstra ms.custom: mvc -ms.date: 01/13/2026 +ms.date: 01/14/2026 uid: fundamentals/middleware/index --- # ASP.NET Core Middleware @@ -15,14 +15,14 @@ uid: fundamentals/middleware/index :::moniker range=">= aspnetcore-8.0" -Middleware is software that's assembled into an app pipeline to handle requests and responses. Each component: +Middleware is software that's assembled into an app pipeline to handle requests and responses. Each middleware: -* 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. +* Chooses whether to pass the request to the next middleware in the pipeline. +* Can perform work before and after the next middleware in the pipeline. Request delegates are used to build the request pipeline. The request delegates handle each HTTP request. -Request delegates are configured using , , and extension methods. An individual request delegate can be specified in-line as an anonymous method (called in-line middleware), or it can be defined in a reusable class. These reusable classes and in-line anonymous methods are *middleware*, also called *middleware components*. Each middleware component in the request pipeline is responsible for invoking the next component in the pipeline or short-circuiting the pipeline. When a middleware short-circuits, it's called a *terminal middleware* because it prevents further middleware from processing the request. +Request delegates are configured using , , and extension methods. An individual request delegate can be specified in-line as an anonymous method (called in-line middleware), or it can be defined in a reusable class. These reusable classes and in-line anonymous methods are *middleware*, also called *middleware components* (not to be confused with [Razor components](xref:blazor/index#components)). Each middleware in the request pipeline is responsible for invoking the next middleware in the pipeline or short-circuiting the pipeline. When a middleware short-circuits, it's called a *terminal middleware* because it prevents further middleware from processing the request. explains the difference between request pipelines in ASP.NET Core and ASP.NET 4.x and provides additional middleware samples. @@ -34,7 +34,7 @@ Standalone Blazor WebAssembly apps run entirely on the client and don't process ## Middleware code analysis -ASP.NET Core includes many compiler platform analyzers that inspect application code for quality. For more information, see +ASP.NET Core includes many compiler platform analyzers that inspect application code for quality. For more information, see . ## Create a middleware pipeline with `WebApplication` @@ -44,7 +44,15 @@ The ASP.NET Core request pipeline consists of a sequence of request delegates, c Each delegate can perform operations before and after the next delegate. Exception-handling delegates should be called early in the pipeline, so they can catch exceptions that occur in later stages of the pipeline. -The simplest possible ASP.NET Core app sets up a single request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. +> [!NOTE] +> To experiment locally with the code examples in this section, create an ASP.NET Core app using the **ASP.NET Core Empty** project template. If using the .NET CLI, the template short name is `web` (`dotnet new web`). + +The simplest possible ASP.NET Core app calls to set up a single terminal middleware request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. + +In the following example: + +* The call to is invoked on every request and writes ':::no-loc text="Hello world!":::' to the response. +* The call to runs the app and blocks the calling thread until host shutdown. ```csharp var builder = WebApplication.CreateBuilder(args); @@ -58,54 +66,98 @@ app.Run(async context => app.Run(); ``` -Chain multiple request delegates together with . The `next` parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by *not* calling the `next` parameter. You can typically perform actions both before and after the `next` delegate, as the following example demonstrates: +Response when accessing the app in a browser at its launch URL: + +> :::no-loc text="Hello world!"::: + +Chain multiple request delegates together with . The `next` parameter represents the next delegate in the pipeline. You can typically perform actions both before and after the `next` delegate. + +The following example demonstrates: + +* Two calls, each writing to the console where work can be performed to write to the response and where work can be performed that doesn't write to the response. +* A terminal request delegate with a call to that writes ':::no-loc text="Hello world!":::' to the response. +* A final call, which never executes because it follows the terminal request delegate. ```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Use(async (context, next) => +{ + Console.WriteLine("Work that can write to the response. (1)"); + await next.Invoke(); + Console.WriteLine("Work that doesn't write to the response. (1)"); +}); + app.Use(async (context, next) => { - // Do work that can write to the Response. + Console.WriteLine("Work that can write to the response. (2)"); await next.Invoke(); - // Do logging or other work that doesn't write to the Response. + Console.WriteLine("Work that doesn't write to the response. (2)"); +}); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello world!"); }); + +app.Use(async (context, next) => +{ + Console.WriteLine("This statement isn't reached. (3)"); + await next.Invoke(); + Console.WriteLine("This statement isn't reached. (3)"); +}); + +app.Run(); ``` -### Short-circuit the request pipeline +In the app's console window when the app is run: + + + +> :::no-loc text="Work that can write to the response. (1)"::: +> :::no-loc text="Work that can write to the response. (2)"::: +> :::no-loc text="Work that doesn't write to the response. (2)"::: +> :::no-loc text="Work that doesn't write to the response. (1)"::: + +When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. -When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. +Don't call `next.Invoke` during or after the response has been sent to the client. After an has started, changes result in an exception. For example, [setting headers or a response status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started) after the response starts. Writing to the response body after calling `next`: -> [!WARNING] -> Don't call `next.Invoke` during or after the response has been sent to the client. After an has started, changes result in an exception. For example, [setting headers and a status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started) after the response starts. Writing to the response body after calling `next`: -> -> * May cause a protocol violation, such as writing more than the stated `Content-Length`. -> * May corrupt the body format, such as writing an HTML footer to a CSS file. -> -> is a useful hint to indicate if headers have been sent or the body has been written to. +* May cause a protocol violation, such as writing more bytes to the response than the stated response's content length (`Content-Length` header value). +* May corrupt the body format, such as writing an HTML footer to a CSS file. + + is a useful hint to indicate if headers have been sent or the body has been written to. For more information, see [Short-circuit middleware after routing](xref:fundamentals/routing#short-circuit-middleware-after-routing). -### `Run` delegates +## `Run` delegates - delegates don't receive a `next` parameter. The first `Run` delegate is always terminal and terminates the pipeline. `Run` is a convention. Some middleware components may expose `Run[Middleware]` methods that run at the end of the pipeline: + delegates don't receive a `next` parameter. The first `Run` delegate always terminates the pipeline. `Run` is also a convention, and some middleware may expose `Run` methods that execute at the end of the pipeline. -```csharp -app.Run(async context => -{ - await context.Response.WriteAsync("Hello from 2nd delegate."); -}); -``` +Any or delegates after the first delegate aren't called. -In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. +## `Use` delegate overload that passes the `HttpContext` to `next` for performance -### Prefer `app.Use` overload that requires passing the context to next + - +Use the non-allocating† extension method for a performance benefit: -The non-allocating extension method: +* Requires passing the to `next`. +* Saves two internal per-request allocations that are required when using the overload without passing the to `next`. -* Requires passing the context to `next`. -* Saves two internal per-request allocations that are required when using the other overload. +> [!NOTE] +> †*Non-allocating* means that the framework avoids creating objects in memory during execution that must be disposed later. -For more information, see [Add new Use middleware extension method (`dotnet/aspnetcore` #31784)](https://github.com/dotnet/aspnetcore/pull/31784). +```csharp +app.Use(async (context, next) => +{ + Console.WriteLine("Work that doesn't write to the response."); + await next.Invoke(context); + Console.WriteLine("Work that doesn't write to the response."); +}); +``` ## Middleware order @@ -127,13 +179,13 @@ preceding creates the x.md.svg file Line 85: [Warning] File 'fundamentals/middleware/index/includes/x.md.svg' referenced by link '~/fundamentals/middleware/index/includes/x.md.svg' will not be built because it is not included in build scope. --> -The **Endpoint** middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. +Endpoint Middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. -The **Routing** middleware in the preceding diagram is shown following **Static Files**. This is the order that the project templates implement by explicitly calling [app.UseRouting](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A). If you don't call `app.UseRouting`, the **Routing** middleware runs at the beginning of the pipeline by default. For more information, see [Routing](xref:fundamentals/routing). +Routing Middleware in the preceding diagram is shown following Static File Middleware. This is the order that the project templates implement by explicitly calling . If you don't call , the Routing Middleware runs at the beginning of the pipeline by default. For more information, see . -The order that middleware components are added in the `Program.cs` file defines the order in which the middleware components are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. +The order that middleware are added in the `Program.cs` file defines the order in which the middleware are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. -The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: +The following highlighted code in `Program.cs` adds security-related middleware in the typical recommended order: ```csharp using Microsoft.AspNetCore.Identity; @@ -188,23 +240,21 @@ app.Run(); In the preceding code: -* Middleware that is not added when creating a new web app with [individual users accounts](xref:security/authentication/identity) is commented out. +* The commented out middleware isn't added when creating a new web app with [individual users accounts](xref:security/authentication/identity). * Not every middleware appears in this exact order, but many do. For example: - * `UseCors`, `UseAuthentication`, and `UseAuthorization` must appear in the order shown. - * `UseCors` currently must appear before `UseResponseCaching`. This requirement is explained in [GitHub issue dotnet/aspnetcore #23218](https://github.com/dotnet/aspnetcore/issues/23218). - * `UseRequestLocalization` must appear before any middleware that might check the request culture, for example, `app.UseStaticFiles()`. - * must be called after `UseRouting` when rate limiting endpoint specific APIs are used. For example, if the [`[EnableRateLimiting]`](xref:Microsoft.AspNetCore.RateLimiting.EnableRateLimitingAttribute) attribute is used, `UseRateLimiter` must be called after `UseRouting`. When calling only global limiters, `UseRateLimiter` can be called before `UseRouting`. + * CORS Middleware (), Authentication Middleware (), and Authorization Middleware () must appear in the order shown. + * CORS Middleware () must appear before Response Caching Middleware () to add CORS headers on every request to include cached responses. For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). + * Request Localization Middleware () must appear before any middleware that might check the request culture, for example, Static File Middleware (). + * Rate Limiting Middleware () must be called after Routing Middleware () when rate limiting endpoint specific APIs are used. For example, if the [`[EnableRateLimiting]` attribute](xref:Microsoft.AspNetCore.RateLimiting.EnableRateLimitingAttribute) is used, Rate Limiting Middleware must be called after Routing Middleware. When calling only global limiters, Rate Limiting Middleware can be called before Routing Middleware. -In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there are multiple valid orderings. For example: +In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there are multiple valid orderings. In the following order, CPU usage could be reduced by caching the compressed response, but the app might end up caching multiple representations of a resource using different compression algorithms, such as Gzip or Brotli: ```csharp app.UseResponseCaching(); app.UseResponseCompression(); ``` -With the preceding code, CPU usage could be reduced by caching the compressed response, but you might end up caching multiple representations of a resource using different compression algorithms such as Gzip or Brotli. - -The following ordering combines static files to allow caching compressed static files: +The following ordering includes Static File Middleware to allow caching compressed static files: ```csharp app.UseResponseCaching(); @@ -212,7 +262,7 @@ app.UseResponseCompression(); app.UseStaticFiles(); ``` -The following `Program.cs` code adds middleware components for common app scenarios: +The following example adds middleware for common app scenarios. Each middleware extension method is exposed on through the namespace: 1. Exception/error handling * When the app runs in the `Development` environment: @@ -251,85 +301,75 @@ app.UseSession(); app.MapRazorPages(); ``` -In the preceding example code, each middleware extension method is exposed on through the namespace. +Static File Middleware is called early in the pipeline so that it can handle static file requests and short-circuit to avoid processing remaining middlewares. The Static File Middleware provides **no** authorization checks. Served files, including those under `wwwroot`, are publicly available. For an approach to secure static files, see . - is the first middleware component added to the pipeline. Therefore, the Exception Handler Middleware catches any exceptions that occur in later calls. +If the request isn't handled by Static File Middleware, it's passed on to Authentication Middleware (), which performs authentication. Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization (and rejection) occurs only after Blazor selects a Razor component, Razor Pages page, or MVC controller and action are selected for execution/rendering. -Static File Middleware is called early in the pipeline so that it can handle requests and short-circuit without going through the remaining components. The Static File Middleware provides **no** authorization checks. Any files served by Static File Middleware, including those under *wwwroot*, are publicly available. For an approach to secure static files, see . - -If the request isn't handled by the Static File Middleware, it's passed on to the Authentication Middleware (), which performs authentication. Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization (and rejection) occurs only after MVC selects a specific Razor Page or MVC controller and action. - -The following example demonstrates a middleware order where requests for static files are handled by Static File Middleware before Response Compression Middleware. Static files aren't compressed with this middleware order. The Razor Pages responses can be compressed. +The following example demonstrates a middleware order where requests for static files are handled by Static File Middleware before Response Compression Middleware, so static files aren't compressed. Static files aren't compressed with this middleware order. Response content after Response Compression Middleware can be compressed. ```csharp -// Static files aren't compressed by Static File Middleware. app.UseStaticFiles(); - app.UseRouting(); - app.UseResponseCompression(); - -app.MapRazorPages(); ``` -For information about Single Page Applications, see . - ## `UseCors` and `UseStaticFiles` order -The order for calling `UseCors` and `UseStaticFiles` depends on the app. For more information, see [UseCors and UseStaticFiles order](xref:security/cors#uc1) +The order for calling and depends on the app. For more information, see [`UseCors` and `UseStaticFiles` order](xref:security/cors#usecors-and-usestaticfiles-order). ### Forwarded Headers Middleware order -[!INCLUDE[](~/includes/ForwardedHeaders.md)] +Run Forwarded Headers Middleware before other middleware to ensure that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). ## Branch the middleware pipeline - extensions are used as a convention for branching the pipeline. `Map` branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. + extensions are used as a convention to branch the request processing pipeline. branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. + +In the following example, `HandleMap1` is called for requests to `/map1`, and `HandleMap2` is called for requests to `/map2`: ```csharp var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); -app.Map("/map1", HandleMapTest1); - -app.Map("/map2", HandleMapTest2); +app.Map("/map1", HandleMap1); +app.Map("/map2", HandleMap2); app.Run(async context => { - await context.Response.WriteAsync("Hello from non-Map delegate."); + await context.Response.WriteAsync("Hello from the non-Map delegate!"); }); app.Run(); -static void HandleMapTest1(IApplicationBuilder app) +static void HandleMap1(IApplicationBuilder app) { app.Run(async context => { - await context.Response.WriteAsync("Map Test 1"); + await context.Response.WriteAsync("Map 1"); }); } -static void HandleMapTest2(IApplicationBuilder app) +static void HandleMap2(IApplicationBuilder app) { app.Run(async context => { - await context.Response.WriteAsync("Map Test 2"); + await context.Response.WriteAsync("Map 2"); }); } ``` -The following table shows the requests and responses from `http://localhost:1234` using the preceding code. +The following table shows the requests and responses using the preceding code. -| Request | Response | -| ------------------- | ---------------------------- | -| localhost:1234 | Hello from non-Map delegate. | -| localhost:1234/map1 | Map Test 1 | -| localhost:1234/map2 | Map Test 2 | -| localhost:1234/map3 | Hello from non-Map delegate. | +Request | Response +--------- | ---------------------------------------------------- +`/` | :::no-loc text="Hello from the non-Map delegate."::: +`/map1` | :::no-loc text="Map 1"::: +`/map2` | :::no-loc text="Map 2"::: +`/map3` | :::no-loc text="Hello from the non-Map delegate."::: -When `Map` is used, the matched path segments are removed from `HttpRequest.Path` and appended to `HttpRequest.PathBase` for each request. +When is used, the matched path segments are removed from and appended to for each request. -`Map` supports nesting, for example: + supports nesting, for example: ```csharp app.Map("/level1", level1App => { @@ -342,7 +382,7 @@ app.Map("/level1", level1App => { }); ``` -`Map` can also match multiple segments at once: + can also match multiple segments at once: ```csharp var builder = WebApplication.CreateBuilder(args); @@ -352,7 +392,7 @@ app.Map("/map1/seg1", HandleMultiSeg); app.Run(async context => { - await context.Response.WriteAsync("Hello from non-Map delegate."); + await context.Response.WriteAsync("Hello from the non-Map delegate."); }); app.Run(); @@ -361,12 +401,12 @@ static void HandleMultiSeg(IApplicationBuilder app) { app.Run(async context => { - await context.Response.WriteAsync("Map Test 1"); + await context.Response.WriteAsync("Map 1 - Segment 1"); }); } ``` - branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable `branch`: + branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable named "`branch`": ```csharp var builder = WebApplication.CreateBuilder(args); @@ -376,7 +416,7 @@ app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch app.Run(async context => { - await context.Response.WriteAsync("Hello from non-Map delegate."); + await context.Response.WriteAsync("Hello from the non-Map delegate."); }); app.Run(); @@ -391,14 +431,14 @@ static void HandleBranch(IApplicationBuilder app) } ``` -The following table shows the requests and responses from `http://localhost:1234` using the previous code: +The following table shows the requests and responses using the previous code: -| Request | Response | -| ----------------------------- | ------------------------------ | -| `localhost:1234` | `Hello from non-Map delegate.` | -| `localhost:1234/?branch=main` | `Branch used = main` | +Request | Response +--- | --- +`/` | :::no-loc text="Hello from the non-Map delegate."::: +`/?branch=main` | :::no-loc text="Branch used = main"::: - also branches the request pipeline based on the result of the given predicate. Unlike with `MapWhen`, this branch is rejoined to the main pipeline if it doesn't contain a terminal middleware: + also branches the request pipeline based on the result of the given predicate. Unlike when calling , this branch is rejoined to the main pipeline if it doesn't contain a terminal middleware: ```csharp var builder = WebApplication.CreateBuilder(args); @@ -409,7 +449,7 @@ app.UseWhen(context => context.Request.Query.ContainsKey("branch"), app.Run(async context => { - await context.Response.WriteAsync("Hello from non-Map delegate."); + await context.Response.WriteAsync("Hello from the non-Map delegate."); }); app.Run(); @@ -423,50 +463,50 @@ void HandleBranchAndRejoin(IApplicationBuilder app) var branchVer = context.Request.Query["branch"]; logger.LogInformation("Branch used = {branchVer}", branchVer); - // Do work that doesn't write to the Response. - await next(); - // Do other work that doesn't write to the Response. + Console.WriteLine("Work that can write to the response."); + await next.Invoke(); + Console.WriteLine("Work that doesn't write to the response."); }); } ``` -In the preceding example, a response of `Hello from non-Map delegate.` is written for all requests. If the request includes a query string variable `branch`, its value is logged before the main pipeline is rejoined. +In the preceding example, a response of ':::no-loc text="Hello from the non-Map delegate.":::' is written for all requests. If the request includes a query string variable named "`branch`," its value is logged before the main pipeline is rejoined. ## Built-in middleware -ASP.NET Core ships with the following middleware components. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with WebApplication](#create-a-middleware-pipeline-with-webapplication) section. - -| Middleware | Description | Order | -| ---------- | ----------- | ----- | -| [Antiforgery](xref:security/anti-request-forgery) | Provides anti-request-forgery support. | After authentication and authorization, before endpoints. | -| [Authentication](xref:security/authentication/identity) | Provides authentication support. | Before `HttpContext.User` is needed. Terminal for OAuth callbacks. | -| [Authorization](xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A) | Provides authorization support. | Immediately after the Authentication Middleware. | -| [Cookie Policy](xref:security/gdpr) | Tracks consent from users for storing personal information and enforces minimum standards for cookie fields, such as `secure` and `SameSite`. | Before middleware that issues cookies. Examples: Authentication, Session, MVC (TempData). | -| [CORS](xref:security/cors) | Configures Cross-Origin Resource Sharing. | Before components that use CORS. `UseCors` currently must go before `UseResponseCaching` due to [this bug](https://github.com/dotnet/aspnetcore/issues/23218).| -| [DeveloperExceptionPage](xref:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware) | Generates a page with error information that is intended for use only in the `Development` environment. | Before components that generate errors. The project templates automatically register this middleware as the first middleware in the pipeline when the environment is `Development`. | -| [Diagnostics](xref:fundamentals/error-handling) | Several separate middlewares that provide a developer exception page, exception handling, status code pages, and the default web page for new apps. | Before components that generate errors. Terminal for exceptions or serving the default web page for new apps. | -| [Forwarded Headers](xref:host-and-deploy/proxy-load-balancer) | Forwards proxied headers onto the current request. | Before components that consume the updated fields. Examples: scheme, host, client IP, method. | -| [Health Check](xref:host-and-deploy/health-checks) | Checks the health of an ASP.NET Core app and its dependencies, such as checking database availability. | Terminal if a request matches a health check endpoint. | -| [Header Propagation](xref:fundamentals/http-requests#header-propagation-middleware) | Propagates HTTP headers from the incoming request to the outgoing HTTP Client requests. | -| [HTTP Logging](xref:fundamentals/http-logging/index) | Logs HTTP Requests and Responses. | At the beginning of the middleware pipeline. | -| [HTTP Method Override](xref:Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions) | Allows an incoming POST request to override the method. | Before components that consume the updated method. | -| [HTTPS Redirection](xref:security/enforcing-ssl#require-https) | Redirect all HTTP requests to HTTPS. | Before components that consume the URL. | -| [HTTP Strict Transport Security (HSTS)](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) | Security enhancement middleware that adds a special response header. | Before responses are sent and after components that modify requests. Examples: Forwarded Headers, URL Rewriting. | -| [MVC](xref:mvc/overview) | Processes requests with MVC/Razor Pages. | Terminal if a request matches a route. | -| [OWIN](xref:fundamentals/owin) | Interop with OWIN-based apps, servers, and middleware. | Terminal if the OWIN Middleware fully processes the request. | -| [Output Caching](xref:performance/caching/output) | Provides support for caching responses based on configuration. | Before components that require caching. `UseRouting` must come before `UseOutputCaching`. `UseCORS` must come before `UseOutputCaching`.| -| [Response Caching](xref:performance/caching/middleware) | Provides support for caching responses. This requires client participation to work. Use output caching for complete server control. | Before components that require caching. `UseCORS` must come before `UseResponseCaching`. Is typically not beneficial for UI apps such as Razor Pages because browsers generally set request headers that prevent caching. [Output caching](xref:performance/caching/output) benefits UI apps.| -| [Request Decompression](xref:fundamentals/middleware/request-decompression) | Provides support for decompressing requests. | Before components that read the request body. | -| [Response Compression](xref:performance/response-compression) | Provides support for compressing responses. | Before components that require compression. | -| [Request Localization](xref:fundamentals/localization) | Provides localization support. | Before localization sensitive components. Must appear after Routing Middleware when using . | -| [Request Timeouts](xref:performance/timeouts) | Provides support for configuring request timeouts, global and per endpoint. | `UseRequestTimeouts` must come after `UseExceptionHandler`, `UseDeveloperExceptionPage`, and `UseRouting`. | -| [Endpoint Routing](xref:fundamentals/routing) | Defines and constrains request routes. | Terminal for matching routes. | -| [SPA](xref:Microsoft.AspNetCore.Builder.SpaApplicationBuilderExtensions.UseSpa%2A) | Handles all requests from this point in the middleware chain by returning the default page for the Single Page Application (SPA) | Late in the chain, so that other middleware for serving static files, MVC actions, etc., takes precedence.| -| [Session](xref:fundamentals/app-state) | Provides support for managing user sessions. | Before components that require Session. | -| [Static Files](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | Terminal if a request matches a file. | -| [URL Rewrite](xref:fundamentals/url-rewriting) | Provides support for rewriting URLs and redirecting requests. | Before components that consume the URL. | -| [W3CLogging](xref:fundamentals/w3c-logger/index) | Generates server access logs in the [W3C Extended Log File Format](https://www.w3.org/TR/WD-logfile.html). | At the beginning of the middleware pipeline. | -| [WebSockets](xref:fundamentals/websockets) | Enables the WebSockets protocol. | Before components that are required to accept WebSocket requests. | +ASP.NET Core ships with the following middleware. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. + +Middleware | Description | Order +--- | --- | --- +[Antiforgery](xref:security/anti-request-forgery) | Provides anti-request-forgery support. | After authentication and authorization, before endpoints. +[Authentication](xref:security/authentication/identity) | Provides authentication support. | Before `HttpContext.User` is needed. Terminal for OAuth callbacks. +[Authorization](xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A) | Provides authorization support. | Immediately after the Authentication Middleware. +[Cookie Policy](xref:security/gdpr) | Tracks consent from users for storing personal information and enforces minimum standards for cookie fields, such as `secure` and `SameSite`. | Before middleware that issues cookies. Examples: Authentication, Session, MVC (TempData). +[CORS](xref:security/cors) | Configures Cross-Origin Resource Sharing. | Before middleware that use CORS. must go before . For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). +[DeveloperExceptionPage](xref:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware) | Generates a page with error information that is intended for use only in the `Development` environment. | Before middleware that generate errors. The project templates automatically register this middleware as the first middleware in the pipeline when the environment is `Development`. +[Diagnostics](xref:fundamentals/error-handling) | Several separate middlewares that provide a developer exception page, exception handling, status code pages, and the default web page for new apps. | Before middleware that generate errors. Terminal for exceptions or serving the default web page for new apps. +[Forwarded Headers](xref:host-and-deploy/proxy-load-balancer) | Forwards proxied headers onto the current request. | Before middleware that consume the updated fields. Examples: scheme, host, client IP, method. +[Health Check](xref:host-and-deploy/health-checks) | Checks the health of an ASP.NET Core app and its dependencies, such as checking database availability. | Terminal if a request matches a health check endpoint. +[Header Propagation](xref:fundamentals/http-requests#header-propagation-middleware) | Propagates HTTP headers from the incoming request to the outgoing HTTP Client requests. +[HTTP Logging](xref:fundamentals/http-logging/index) | Logs HTTP Requests and Responses. | At the beginning of the middleware pipeline. +[HTTP Method Override](xref:Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions) | Allows an incoming POST request to override the method. | Before middleware that consume the updated method. +[HTTPS Redirection](xref:security/enforcing-ssl#require-https) | Redirect all HTTP requests to HTTPS. | Before middleware that consume the URL. +[HTTP Strict Transport Security (HSTS)](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) | Security enhancement middleware that adds a special response header. | Before responses are sent and after middleware that modify requests. Examples: Forwarded Headers, URL Rewriting. +[MVC](xref:mvc/overview) | Processes requests with MVC/Razor Pages. | Terminal if a request matches a route. +[OWIN](xref:fundamentals/owin) | Interop with OWIN-based apps, servers, and middleware. | Terminal if the OWIN Middleware fully processes the request. +[Output Caching](xref:performance/caching/output) | Provides support for caching responses based on configuration. | Before middleware that require caching. must come before `UseOutputCaching`. must come before `UseOutputCaching`. +[Response Caching](xref:performance/caching/middleware) | Provides support for caching responses. This requires client participation to work. Use output caching for complete server control. | Before middleware that require caching. must come before . Response caching isn't typically beneficial for UI apps, such as Razor Pages, because browsers generally set request headers that prevent caching. [Output caching](xref:performance/caching/output) benefits UI apps. +[Request Decompression](xref:fundamentals/middleware/request-decompression) | Provides support for decompressing requests. | Before middleware that read the request body. +[Response Compression](xref:performance/response-compression) | Provides support for compressing responses. | Before middleware that require compression. +[Request Localization](xref:fundamentals/localization) | Provides localization support. | Before localization sensitive middleware. Must appear after Routing Middleware when using . +[Request Timeouts](xref:performance/timeouts) | Provides support for configuring request timeouts, global and per endpoint. | must come after , , and . +[Endpoint Routing](xref:fundamentals/routing) | Defines and constrains request routes. | Terminal for matching routes. +[SPA](xref:Microsoft.AspNetCore.Builder.SpaApplicationBuilderExtensions.UseSpa%2A) | Handles all requests from this point in the middleware chain by returning the default page for the Single Page Application (SPA) | Appears late in the pipeline, so that other middleware for serving static files, such as MVC actions, take precedence. +[Session](xref:fundamentals/app-state) | Provides support for managing user sessions. | Before middleware that require Session. +[Static Files](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | Terminal if a request matches a file. +[URL Rewrite](xref:fundamentals/url-rewriting) | Provides support for rewriting URLs and redirecting requests. | Before middleware that consume the URL. +[W3CLogging](xref:fundamentals/w3c-logger/index) | Generates server access logs in the [W3C Extended Log File Format](https://www.w3.org/TR/WD-logfile.html). | At the beginning of the middleware pipeline. +[WebSockets](xref:fundamentals/websockets) | Enables the WebSockets protocol. | Before middleware that are required to accept WebSocket requests. ## Additional resources diff --git a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md index 0a4eb118614b..8742af58d63e 100644 --- a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md +++ b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md @@ -1,7 +1,5 @@ :::moniker range="= aspnetcore-7.0" -By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Steve Smith](https://ardalis.com/) - 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. @@ -245,11 +243,11 @@ For information about Single Page Applications, see the guides for the [React](x ## UseCors and UseStaticFiles order -The order for calling `UseCors` and `UseStaticFiles` depends on the app. For more information, see [UseCors and UseStaticFiles order](xref:security/cors#uc1) +The order for calling `UseCors` and `UseStaticFiles` depends on the app. For more information, see [`UseCors` and `UseStaticFiles` order](xref:security/cors#usecors-and-usestaticfiles-order). ### Forwarded Headers Middleware order -[!INCLUDE[](~/includes/ForwardedHeaders.md)] +Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). ## Branch the middleware pipeline @@ -451,8 +449,6 @@ ASP.NET Core ships with the following middleware components. The *Order* column :::moniker range="= aspnetcore-6.0" -By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Steve Smith](https://ardalis.com/) - 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. @@ -691,11 +687,11 @@ For information about Single Page Applications, see the guides for the [React](x ## UseCors and UseStaticFiles order -The order for calling `UseCors` and `UseStaticFiles` depends on the app. For more information, see [UseCors and UseStaticFiles order](xref:security/cors#uc1) +The order for calling `UseCors` and `UseStaticFiles` depends on the app. For more information, see [`UseCors` and `UseStaticFiles` order](xref:security/cors#usecors-and-usestaticfiles-order). ### Forwarded Headers Middleware order -[!INCLUDE[](~/includes/ForwardedHeaders.md)] +Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). ## Branch the middleware pipeline @@ -896,8 +892,6 @@ ASP.NET Core ships with the following middleware components. The *Order* column :::moniker range="< aspnetcore-6.0" -By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Steve Smith](https://ardalis.com/) - 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. @@ -1122,7 +1116,7 @@ For more details on SPAs, see the guides for the [React](xref:spa/react) and [An ### Forwarded Headers Middleware order -[!INCLUDE[](~/includes/ForwardedHeaders.md)] +Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). ## Branch the middleware pipeline diff --git a/aspnetcore/host-and-deploy/linux-nginx.md b/aspnetcore/host-and-deploy/linux-nginx.md index 235ce1d02275..1150942a84fb 100644 --- a/aspnetcore/host-and-deploy/linux-nginx.md +++ b/aspnetcore/host-and-deploy/linux-nginx.md @@ -106,7 +106,7 @@ For the purposes of this guide, a single instance of Nginx is used. It runs on t Because requests are forwarded by reverse proxy, use the [Forwarded Headers Middleware](xref:host-and-deploy/proxy-load-balancer) from the [`Microsoft.AspNetCore.HttpOverrides`](https://www.nuget.org/packages/Microsoft.AspNetCore.HttpOverrides) package, which is automatically included in ASP.NET Core apps via the [shared framework's `Microsoft.AspNetCore.App` metapackage](xref:fundamentals/metapackage-app). The middleware updates the `Request.Scheme`, using the `X-Forwarded-Proto` header, so that redirect URIs and other security policies work correctly. -[!INCLUDE[](~/includes/ForwardedHeaders.md)] +Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). Invoke the method before calling other middleware. Configure the middleware to forward the `X-Forwarded-For` and `X-Forwarded-Proto` headers: diff --git a/aspnetcore/host-and-deploy/linux-nginx/includes/linux-nginx5.md b/aspnetcore/host-and-deploy/linux-nginx/includes/linux-nginx5.md index 06ebd2efa333..94cdecc2ab1e 100644 --- a/aspnetcore/host-and-deploy/linux-nginx/includes/linux-nginx5.md +++ b/aspnetcore/host-and-deploy/linux-nginx/includes/linux-nginx5.md @@ -79,7 +79,7 @@ For the purposes of this guide, a single instance of Nginx is used. It runs on t Because requests are forwarded by reverse proxy, use the [Forwarded Headers Middleware](xref:host-and-deploy/proxy-load-balancer) from the [`Microsoft.AspNetCore.HttpOverrides`](https://www.nuget.org/packages/Microsoft.AspNetCore.HttpOverrides) package. The middleware updates the `Request.Scheme`, using the `X-Forwarded-Proto` header, so that redirect URIs and other security policies work correctly. -[!INCLUDE[](~/includes/ForwardedHeaders.md)] +Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). Invoke the method at the top of `Program.cs` before calling other middleware. Configure the middleware to forward the `X-Forwarded-For` and `X-Forwarded-Proto` headers: @@ -522,9 +522,9 @@ For the purposes of this guide, a single instance of Nginx is used. It runs on t Because requests are forwarded by reverse proxy, use the [Forwarded Headers Middleware](xref:host-and-deploy/proxy-load-balancer) from the [`Microsoft.AspNetCore.HttpOverrides`](https://www.nuget.org/packages/Microsoft.AspNetCore.HttpOverrides) package. The middleware updates the `Request.Scheme`, using the `X-Forwarded-Proto` header, so that redirect URIs and other security policies work correctly. -[!INCLUDE[](~/includes/ForwardedHeaders.md)] +Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). -Invoke the method at the top of `Startup.Configure` before calling other middleware. Configure the middleware to forward the `X-Forwarded-For` and `X-Forwarded-Proto` headers: +Invoke the method at the top of the request processing pipeline before calling other middleware. Configure the middleware to forward the `X-Forwarded-For` and `X-Forwarded-Proto` headers: ```csharp using Microsoft.AspNetCore.HttpOverrides; diff --git a/aspnetcore/host-and-deploy/proxy-load-balancer.md b/aspnetcore/host-and-deploy/proxy-load-balancer.md index f09f9a9559af..8e130b00fe4e 100644 --- a/aspnetcore/host-and-deploy/proxy-load-balancer.md +++ b/aspnetcore/host-and-deploy/proxy-load-balancer.md @@ -66,8 +66,6 @@ Outside of using [IIS Integration](xref:host-and-deploy/iis/index#enable-the-iis Configure the middleware with to forward the [`X-Forwarded-For`](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-For) and [`X-Forwarded-Proto`](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto) headers. - - ### Forwarded Headers Middleware order [Forwarded Headers Middleware](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/HttpOverrides/src/ForwardedHeadersOptions.cs) should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. Forwarded Headers Middleware can run after diagnostics and error handling, but it must be run before calling : diff --git a/aspnetcore/includes/ForwardedHeaders.md b/aspnetcore/includes/ForwardedHeaders.md deleted file mode 100644 index b95a02685f87..000000000000 --- a/aspnetcore/includes/ForwardedHeaders.md +++ /dev/null @@ -1 +0,0 @@ -Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after diagnostics and error handling middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#fhmo). \ No newline at end of file From 1c13aae1d9073efe331614bd02fd4f38da5ca384 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:19:15 -0500 Subject: [PATCH 05/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 62 ++++++++----------- .../index/includes/mermaid-instructions.txt | 12 ++++ 2 files changed, 39 insertions(+), 35 deletions(-) create mode 100644 aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 6b08a5e09b74..cfc83f5b6b25 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -6,7 +6,7 @@ description: Learn about ASP.NET Core middleware and the request pipeline. monikerRange: '>= aspnetcore-3.0' ms.author: tdykstra ms.custom: mvc -ms.date: 01/14/2026 +ms.date: 01/15/2026 uid: fundamentals/middleware/index --- # ASP.NET Core Middleware @@ -22,7 +22,7 @@ Middleware is software that's assembled into an app pipeline to handle requests Request delegates are used to build the request pipeline. The request delegates handle each HTTP request. -Request delegates are configured using , , and extension methods. An individual request delegate can be specified in-line as an anonymous method (called in-line middleware), or it can be defined in a reusable class. These reusable classes and in-line anonymous methods are *middleware*, also called *middleware components* (not to be confused with [Razor components](xref:blazor/index#components)). Each middleware in the request pipeline is responsible for invoking the next middleware in the pipeline or short-circuiting the pipeline. When a middleware short-circuits, it's called a *terminal middleware* because it prevents further middleware from processing the request. +Request delegates are configured using , , and extension methods. An individual request delegate can be specified inline as an anonymous method (called inline middleware), or it can be defined in a reusable class. These reusable classes and inline anonymous methods are *middleware*, also called *middleware components* (not to be confused with [Razor components](xref:blazor/index#components) or [View components](xref:mvc/views/view-components)). Each middleware in the request pipeline is responsible for invoking the next middleware in the pipeline or short-circuiting the pipeline. When a middleware short-circuits, it's called a *terminal middleware* because it prevents further middleware from processing the request. explains the difference between request pipelines in ASP.NET Core and ASP.NET 4.x and provides additional middleware samples. @@ -51,7 +51,7 @@ The simplest possible ASP.NET Core app calls is invoked on every request and writes ':::no-loc text="Hello world!":::' to the response. +* The call to is invoked on every request and writes ":::no-loc text="Hello world!":::" to the response. * The call to runs the app and blocks the calling thread until host shutdown. ```csharp @@ -74,8 +74,8 @@ Chain multiple request delegates together with calls, each writing to the console where work can be performed to write to the response and where work can be performed that doesn't write to the response. -* A terminal request delegate with a call to that writes ':::no-loc text="Hello world!":::' to the response. +* Two calls, each writing to the console where work can be performed to write to the response (`context.Response`, ) and where work can be performed that doesn't write to the response after the `next` parameter is invoked. +* A terminal request delegate with a call to that writes ":::no-loc text="Hello world!":::" to the response. * A final call, which never executes because it follows the terminal request delegate. ```csharp @@ -121,20 +121,20 @@ In the app's console window when the app is run: > :::no-loc text="Work that doesn't write to the response. (2)"::: > :::no-loc text="Work that doesn't write to the response. (1)"::: -When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. +When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the terminal middleware still processes code after their `next.Invoke` statements. -Don't call `next.Invoke` during or after the response has been sent to the client. After an has started, changes result in an exception. For example, [setting headers or a response status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started) after the response starts. Writing to the response body after calling `next`: +Don't call `next.Invoke` during or after the response has been sent to the client. After an has started, changes result in an exception. For example, [setting headers or a response status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started) after the response starts. Writing to the response body after calling `next` may: -* May cause a protocol violation, such as writing more bytes to the response than the stated response's content length (`Content-Length` header value). -* May corrupt the body format, such as writing an HTML footer to a CSS file. +* Cause a protocol violation, such as writing more bytes to the response than the stated response's content length (`Content-Length` header value). +* Corrupt the body format, such as writing an HTML footer to a CSS file. - is a useful hint to indicate if headers have been sent or the body has been written to. +Call to determine if headers have been sent or the body has been written to. For more information, see [Short-circuit middleware after routing](xref:fundamentals/routing#short-circuit-middleware-after-routing). -## `Run` delegates +## `Run` delegate - delegates don't receive a `next` parameter. The first `Run` delegate always terminates the pipeline. `Run` is also a convention, and some middleware may expose `Run` methods that execute at the end of the pipeline. +A delegate doesn't receive a `next` parameter. The first `Run` delegate always terminates the pipeline. `Run` is also a convention, and some middleware may expose `Run` methods that execute at the end of the pipeline. Any or delegates after the first delegate aren't called. @@ -142,10 +142,14 @@ Any or =6.0. --> + + Use the non-allocating† extension method for a performance benefit: * Requires passing the to `next`. -* Saves two internal per-request allocations that are required when using the overload without passing the to `next`. +* Saves two internal per-request allocations that are normally required when using the overload that doesn't pass the to `next`. > [!NOTE] > †*Non-allocating* means that the framework avoids creating objects in memory during execution that must be disposed later. @@ -153,32 +157,20 @@ Use the non-allocating† { - Console.WriteLine("Work that doesn't write to the response."); + Console.WriteLine("Work that can write to the response."); await next.Invoke(context); Console.WriteLine("Work that doesn't write to the response."); -}); +}); ``` +If you don't plan to call `next.Invoke` because your goal is to terminate the pipeline, don't call this extension method. Use a [`Run` delegate](#run-delegate) instead. + ## Middleware order The following diagram shows the complete request processing pipeline for ASP.NET Core MVC and Razor Pages apps. You can see how, in a typical app, existing middlewares are ordered and where custom middlewares are added. You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios. ![ASP.NET Core middleware pipeline](~/fundamentals/middleware/index/_static/middleware-pipeline.svg) - - Endpoint Middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. Routing Middleware in the preceding diagram is shown following Static File Middleware. This is the order that the project templates implement by explicitly calling . If you don't call , the Routing Middleware runs at the beginning of the pipeline by default. For more information, see . @@ -341,7 +333,7 @@ app.Run(async context => app.Run(); -static void HandleMap1(IApplicationBuilder app) +private static void HandleMap1(IApplicationBuilder app) { app.Run(async context => { @@ -349,7 +341,7 @@ static void HandleMap1(IApplicationBuilder app) }); } -static void HandleMap2(IApplicationBuilder app) +private static void HandleMap2(IApplicationBuilder app) { app.Run(async context => { @@ -397,7 +389,7 @@ app.Run(async context => app.Run(); -static void HandleMultiSeg(IApplicationBuilder app) +private static void HandleMultiSeg(IApplicationBuilder app) { app.Run(async context => { @@ -421,7 +413,7 @@ app.Run(async context => app.Run(); -static void HandleBranch(IApplicationBuilder app) +private static void HandleBranch(IApplicationBuilder app) { app.Run(async context => { @@ -454,7 +446,7 @@ app.Run(async context => app.Run(); -void HandleBranchAndRejoin(IApplicationBuilder app) +private void HandleBranchAndRejoin(IApplicationBuilder app) { var logger = app.ApplicationServices.GetRequiredService>(); @@ -470,7 +462,7 @@ void HandleBranchAndRejoin(IApplicationBuilder app) } ``` -In the preceding example, a response of ':::no-loc text="Hello from the non-Map delegate.":::' is written for all requests. If the request includes a query string variable named "`branch`," its value is logged before the main pipeline is rejoined. +In the preceding example, a response of ":::no-loc text="Hello from the non-Map delegate.":::" is written for all requests. If the request includes a query string variable named "`branch`," its value is logged before the main pipeline is rejoined. ## Built-in middleware diff --git a/aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt b/aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt new file mode 100644 index 000000000000..28e1b6dcdef5 --- /dev/null +++ b/aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt @@ -0,0 +1,12 @@ +See mermaid diagrams in https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/middleware/index/includes + +Install CLI mermaid to make SVGs +npm install -g mermaid-cli + +remove ```mermaid and closing ``` +mermaid -s x.md +preceding creates the x.md.svg file + +![ASP.NET SVG middleware pipeline](~/fundamentals/middleware/index/includes/x.md.svg) +Line 85: [Warning] File 'fundamentals/middleware/index/includes/x.md.svg' referenced by link +'~/fundamentals/middleware/index/includes/x.md.svg' will not be built because it is not included in build scope. From 82ab194c744e8430c5b356887a4ff428d2e50ea0 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:20:19 -0500 Subject: [PATCH 06/16] Remove Mermaid files --- .../middleware/index/includes/VertGraph.md | 30 --------------- .../index/includes/mermaid-instructions.txt | 12 ------ .../middleware-pipeline.mermaid-short.md | 29 -------------- .../middleware-pipeline.mermaid-short2.md | 22 ----------- .../includes/middleware-pipeline.mermaid.md | 38 ------------------- .../index/includes/midpipe-request.md | 19 ---------- .../index/includes/shortSequence.md | 29 -------------- .../index/includes/shorterSequence2.md | 23 ----------- .../middleware/index/includes/x.md | 27 ------------- .../middleware/index/includes/x.md.svg | 13 ------- 10 files changed, 242 deletions(-) delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/VertGraph.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short2.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/midpipe-request.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/shortSequence.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/shorterSequence2.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/x.md delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/x.md.svg diff --git a/aspnetcore/fundamentals/middleware/index/includes/VertGraph.md b/aspnetcore/fundamentals/middleware/index/includes/VertGraph.md deleted file mode 100644 index abc888feefec..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/VertGraph.md +++ /dev/null @@ -1,30 +0,0 @@ -```mermaid -graph TD; - subgraph Request-Response - Request((Request)) - Response((Response)) - end - Request--->ExceptionHandler - ExceptionHandler--->HSTS - HSTS--->HttpsRedirection - HttpsRedirection--->StaticFiles - StaticFiles--->Routing - Routing--->CORS - CORS--->Authentication - Authentication--->Authorization - Authorization--->Custom1 - Custom1--->Endpoint - - Endpoint--->Custom1 - Custom1--->Authorization - Authorization--->Authentication - Authentication--->CORS - CORS--->Routing - Routing--->StaticFiles - StaticFiles--->HttpsRedirection - HttpsRedirection--->HSTS - HSTS--->ExceptionHandler - ExceptionHandler--->Response - - -``` diff --git a/aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt b/aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt deleted file mode 100644 index 28e1b6dcdef5..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/mermaid-instructions.txt +++ /dev/null @@ -1,12 +0,0 @@ -See mermaid diagrams in https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/middleware/index/includes - -Install CLI mermaid to make SVGs -npm install -g mermaid-cli - -remove ```mermaid and closing ``` -mermaid -s x.md -preceding creates the x.md.svg file - -![ASP.NET SVG middleware pipeline](~/fundamentals/middleware/index/includes/x.md.svg) -Line 85: [Warning] File 'fundamentals/middleware/index/includes/x.md.svg' referenced by link -'~/fundamentals/middleware/index/includes/x.md.svg' will not be built because it is not included in build scope. diff --git a/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short.md b/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short.md deleted file mode 100644 index e7a4bce1181c..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short.md +++ /dev/null @@ -1,29 +0,0 @@ -```mermaid -sequenceDiagram - participant Client - participant ASP.NET Core App - participant ExceptionHandler - participant StaticFiles - participant Routing - participant Cors - participant Authentication - participant CustomMiddleware1 - participant Endpoint - - Client->>ASP.NET Core App: Request - ASP.NET Core App->>ExceptionHandler: Request - ExceptionHandler->>StaticFiles: Request - StaticFiles->>Routing: Request - Routing->>Cors: Request - Cors->>Authentication: Request - Authentication->>CustomMiddleware1: Request - CustomMiddleware1->>Endpoint: Request - Endpoint-->>CustomMiddleware1: Response - CustomMiddleware1-->>Authentication: Response - Authentication-->>Cors: Response - Cors-->>Routing: Response - Routing-->>StaticFiles: Response - StaticFiles-->>ExceptionHandler: Response - ExceptionHandler-->>ASP.NET Core App: Response - ASP.NET Core App-->>Client: Response -``` diff --git a/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short2.md b/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short2.md deleted file mode 100644 index edcb826acd17..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid-short2.md +++ /dev/null @@ -1,22 +0,0 @@ -```mermaid -sequenceDiagram - participant Client - participant ASP.NET Core App - participant StaticFiles - participant Routing - participant Authentication - participant CustomMiddleware1 - participant Endpoint - - Client->>ASP.NET Core App: Request - ASP.NET Core App->>StaticFiles: Request - StaticFiles->>Routing: Request - Routing->>Authentication: Request - Authentication->>CustomMiddleware1: Request - CustomMiddleware1->>Endpoint: Request - Endpoint-->>CustomMiddleware1: Response - CustomMiddleware1-->>Authentication: Response - Authentication-->>Routing: Response - Routing-->>StaticFiles: Response - StaticFiles-->>ASP.NET Core App: Response - ASP.NET Core App-->>Client: Response diff --git a/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid.md b/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid.md deleted file mode 100644 index 5b82555baee6..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/middleware-pipeline.mermaid.md +++ /dev/null @@ -1,38 +0,0 @@ -```mermaid -sequenceDiagram - participant Client - participant ASP.NET Core App - participant ExceptionHandler - participant HSTS - participant HttpsRedirection - participant StaticFiles - participant Routing - participant Cors - participant Authentication - participant Authorization - participant CustomMiddleware1 - participant Endpoint - - Client->>ASP.NET Core App: Request - ASP.NET Core App->>ExceptionHandler: Request - ExceptionHandler->>HSTS: Request - HSTS->>HttpsRedirection: Request - HttpsRedirection->>StaticFiles: Request - StaticFiles->>Routing: Request - Routing->>Cors: Request - Cors->>Authentication: Request - Authentication->>Authorization: Request - Authorization->>CustomMiddleware1: Request - CustomMiddleware1->>Endpoint: Request - Endpoint-->>CustomMiddleware1: Response - CustomMiddleware1-->>Authorization: Response - Authorization-->>Authentication: Response - Authentication-->>Cors: Response - Cors-->>Routing: Response - Routing-->>StaticFiles: Response - StaticFiles-->>HttpsRedirection: Response - HttpsRedirection-->>HSTS: Response - HSTS-->>ExceptionHandler: Response - ExceptionHandler-->>ASP.NET Core App: Response - ASP.NET Core App-->>Client: Response -``` \ No newline at end of file diff --git a/aspnetcore/fundamentals/middleware/index/includes/midpipe-request.md b/aspnetcore/fundamentals/middleware/index/includes/midpipe-request.md deleted file mode 100644 index 396cf5fb1368..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/midpipe-request.md +++ /dev/null @@ -1,19 +0,0 @@ -```mermaid -graph TD; - subgraph Request Pipeline - A[Exception Handling] --> B; - B[HTTPS Redirection] --> C[Static Files]; - C --> D[Routing]; - D --> E[Authentication]; - E --> F[CORS]; - F --> G[Custom Middleware]; - end; - - subgraph Response Pipeline - G --> F; - F --> E; - E --> D; - D --> C; - C --> B; - B --> A; - end; diff --git a/aspnetcore/fundamentals/middleware/index/includes/shortSequence.md b/aspnetcore/fundamentals/middleware/index/includes/shortSequence.md deleted file mode 100644 index 9365568d39d8..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/shortSequence.md +++ /dev/null @@ -1,29 +0,0 @@ -```mermaid -sequenceDiagram - participant Client - participant ASP.NET Core App - participant ExceptionHandler - participant StaticFiles - participant Routing - participant Cors - participant Authentication - participant CustomMiddleware1 - participant Endpoint - - Client->>ASP.NET Core App: Request - ASP.NET Core App->>ExceptionHandler: Request - ExceptionHandler->>StaticFiles: Request - StaticFiles->>Routing: Request - Routing->>Cors: Request - Cors->>Authentication: Request - Authentication->>CustomMiddleware1: Request - CustomMiddleware1->>Endpoint: Request - Endpoint-->>CustomMiddleware1: Response - CustomMiddleware1-->>Authentication: Response - Authentication-->>Cors: Response - Cors-->>Routing: Response - Routing-->>StaticFiles: Response - StaticFiles-->>ExceptionHandler: Response - ExceptionHandler-->>ASP.NET Core App: Response - ASP.NET Core App-->>Client: Response -``` \ No newline at end of file diff --git a/aspnetcore/fundamentals/middleware/index/includes/shorterSequence2.md b/aspnetcore/fundamentals/middleware/index/includes/shorterSequence2.md deleted file mode 100644 index a6a54d1bd2d5..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/shorterSequence2.md +++ /dev/null @@ -1,23 +0,0 @@ -```mermaid -sequenceDiagram - participant Client - participant ASP.NET Core App - participant StaticFiles - participant Routing - participant Authentication - participant CustomMiddleware1 - participant Endpoint - - Client->>ASP.NET Core App: Request - ASP.NET Core App->>StaticFiles: Request - StaticFiles->>Routing: Request - Routing->>Authentication: Request - Authentication->>CustomMiddleware1: Request - CustomMiddleware1->>Endpoint: Request - Endpoint-->>CustomMiddleware1: Response - CustomMiddleware1-->>Authentication: Response - Authentication-->>Routing: Response - Routing-->>StaticFiles: Response - StaticFiles-->>ASP.NET Core App: Response - ASP.NET Core App-->>Client: Response -``` \ No newline at end of file diff --git a/aspnetcore/fundamentals/middleware/index/includes/x.md b/aspnetcore/fundamentals/middleware/index/includes/x.md deleted file mode 100644 index d642983c0e71..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/x.md +++ /dev/null @@ -1,27 +0,0 @@ -sequenceDiagram - participant Client - participant ASP.NET Core App - participant ExceptionHandler - participant StaticFiles - participant Routing - participant Cors - participant Authentication - participant CustomMiddleware1 - participant Endpoint - - Client->>ASP.NET Core App: Request - ASP.NET Core App->>ExceptionHandler: Request - ExceptionHandler->>StaticFiles: Request - StaticFiles->>Routing: Request - Routing->>Cors: Request - Cors->>Authentication: Request - Authentication->>CustomMiddleware1: Request - CustomMiddleware1->>Endpoint: Request - Endpoint-->>CustomMiddleware1: Response - CustomMiddleware1-->>Authentication: Response - Authentication-->>Cors: Response - Cors-->>Routing: Response - Routing-->>StaticFiles: Response - StaticFiles-->>ExceptionHandler: Response - ExceptionHandler-->>ASP.NET Core App: Response - ASP.NET Core App-->>Client: Response diff --git a/aspnetcore/fundamentals/middleware/index/includes/x.md.svg b/aspnetcore/fundamentals/middleware/index/includes/x.md.svg deleted file mode 100644 index 0965a4da7202..000000000000 --- a/aspnetcore/fundamentals/middleware/index/includes/x.md.svg +++ /dev/null @@ -1,13 +0,0 @@ -Client -ASP.NET Core App -ExceptionHandler -StaticFiles -Routing -Cors -Authentication -CustomMiddleware1 -Endpoint -ClientASP.NET Core AppExceptionHandlerStaticFilesRoutingCorsAuthenticationCustomMiddleware1EndpointRequestRequestRequestRequestRequestRequestRequestRequestResponseResponseResponseResponseResponseResponseResponseResponse \ No newline at end of file From e50cff077923ad3499ede16a02ca53edbb76f70b Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 15 Jan 2026 12:26:28 -0500 Subject: [PATCH 07/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 269 +++++++-------- .../index/_static/middleware-pipeline.svg | 324 ------------------ 2 files changed, 117 insertions(+), 476 deletions(-) delete mode 100644 aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index cfc83f5b6b25..27f55701a2c4 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -142,9 +142,9 @@ Any or =6.0. --> - + Use the non-allocating† extension method for a performance benefit: @@ -165,154 +165,6 @@ app.Use(async (context, next) => If you don't plan to call `next.Invoke` because your goal is to terminate the pipeline, don't call this extension method. Use a [`Run` delegate](#run-delegate) instead. -## Middleware order - -The following diagram shows the complete request processing pipeline for ASP.NET Core MVC and Razor Pages apps. You can see how, in a typical app, existing middlewares are ordered and where custom middlewares are added. You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios. - -![ASP.NET Core middleware pipeline](~/fundamentals/middleware/index/_static/middleware-pipeline.svg) - -Endpoint Middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. - -Routing Middleware in the preceding diagram is shown following Static File Middleware. This is the order that the project templates implement by explicitly calling . If you don't call , the Routing Middleware runs at the beginning of the pipeline by default. For more information, see . - -The order that middleware are added in the `Program.cs` file defines the order in which the middleware are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. - -The following highlighted code in `Program.cs` adds security-related middleware in the typical recommended order: - -```csharp -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using WebMiddleware.Data; - -var builder = WebApplication.CreateBuilder(args); - -var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") - ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); -builder.Services.AddDbContext(options => - options.UseSqlServer(connectionString)); -builder.Services.AddDatabaseDeveloperPageExceptionFilter(); - -builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) - .AddEntityFrameworkStores(); -builder.Services.AddRazorPages(); -builder.Services.AddControllersWithViews(); - -var app = builder.Build(); - -if (app.Environment.IsDevelopment()) -{ - app.UseMigrationsEndPoint(); -} -else -{ - app.UseExceptionHandler("/Error"); - app.UseHsts(); -} - -app.UseHttpsRedirection(); -app.UseStaticFiles(); -// app.UseCookiePolicy(); - -app.UseRouting(); -// app.UseRateLimiter(); -// app.UseRequestLocalization(); -// app.UseCors(); - -app.UseAuthentication(); -app.UseAuthorization(); -// app.UseSession(); -// app.UseResponseCompression(); -// app.UseResponseCaching(); - -app.MapRazorPages(); -app.MapDefaultControllerRoute(); - -app.Run(); -``` - -In the preceding code: - -* The commented out middleware isn't added when creating a new web app with [individual users accounts](xref:security/authentication/identity). -* Not every middleware appears in this exact order, but many do. For example: - * CORS Middleware (), Authentication Middleware (), and Authorization Middleware () must appear in the order shown. - * CORS Middleware () must appear before Response Caching Middleware () to add CORS headers on every request to include cached responses. For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). - * Request Localization Middleware () must appear before any middleware that might check the request culture, for example, Static File Middleware (). - * Rate Limiting Middleware () must be called after Routing Middleware () when rate limiting endpoint specific APIs are used. For example, if the [`[EnableRateLimiting]` attribute](xref:Microsoft.AspNetCore.RateLimiting.EnableRateLimitingAttribute) is used, Rate Limiting Middleware must be called after Routing Middleware. When calling only global limiters, Rate Limiting Middleware can be called before Routing Middleware. - -In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there are multiple valid orderings. In the following order, CPU usage could be reduced by caching the compressed response, but the app might end up caching multiple representations of a resource using different compression algorithms, such as Gzip or Brotli: - -```csharp -app.UseResponseCaching(); -app.UseResponseCompression(); -``` - -The following ordering includes Static File Middleware to allow caching compressed static files: - -```csharp -app.UseResponseCaching(); -app.UseResponseCompression(); -app.UseStaticFiles(); -``` - -The following example adds middleware for common app scenarios. Each middleware extension method is exposed on through the namespace: - -1. Exception/error handling - * When the app runs in the `Development` environment: - * Developer Exception Page Middleware () reports app runtime errors. - * Database Error Page Middleware () reports database runtime errors. - * When the app runs in the `Production` environment: - * Exception Handler Middleware () catches exceptions thrown in the following middlewares. - * HTTP Strict Transport Security Protocol (HSTS) Middleware () adds the `Strict-Transport-Security` header. -1. HTTPS Redirection Middleware () redirects HTTP requests to HTTPS. -1. Static File Middleware () returns static files and short-circuits further request processing. -1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR) regulations. -1. Routing Middleware () to route requests. -1. Authentication Middleware () attempts to authenticate the user before they're allowed access to secure resources. -1. Authorization Middleware () authorizes a user to access secure resources. -1. Session Middleware () establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before MVC Middleware. -1. Endpoint Routing Middleware ( with ) to add Razor Pages endpoints to the request pipeline. - -```csharp -if (env.IsDevelopment()) -{ - app.UseDeveloperExceptionPage(); - app.UseDatabaseErrorPage(); -} -else -{ - app.UseExceptionHandler("/Error"); - app.UseHsts(); -} -app.UseHttpsRedirection(); -app.UseStaticFiles(); -app.UseCookiePolicy(); -app.UseRouting(); -app.UseAuthentication(); -app.UseAuthorization(); -app.UseSession(); -app.MapRazorPages(); -``` - -Static File Middleware is called early in the pipeline so that it can handle static file requests and short-circuit to avoid processing remaining middlewares. The Static File Middleware provides **no** authorization checks. Served files, including those under `wwwroot`, are publicly available. For an approach to secure static files, see . - -If the request isn't handled by Static File Middleware, it's passed on to Authentication Middleware (), which performs authentication. Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization (and rejection) occurs only after Blazor selects a Razor component, Razor Pages page, or MVC controller and action are selected for execution/rendering. - -The following example demonstrates a middleware order where requests for static files are handled by Static File Middleware before Response Compression Middleware, so static files aren't compressed. Static files aren't compressed with this middleware order. Response content after Response Compression Middleware can be compressed. - -```csharp -app.UseStaticFiles(); -app.UseRouting(); -app.UseResponseCompression(); -``` - -## `UseCors` and `UseStaticFiles` order - -The order for calling and depends on the app. For more information, see [`UseCors` and `UseStaticFiles` order](xref:security/cors#usecors-and-usestaticfiles-order). - -### Forwarded Headers Middleware order - -Run Forwarded Headers Middleware before other middleware to ensure that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). - ## Branch the middleware pipeline extensions are used as a convention to branch the request processing pipeline. branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. @@ -464,6 +316,119 @@ private void HandleBranchAndRejoin(IApplicationBuilder app) In the preceding example, a response of ":::no-loc text="Hello from the non-Map delegate.":::" is written for all requests. If the request includes a query string variable named "`branch`," its value is logged before the main pipeline is rejoined. +## Middleware order + +The order that middleware appears in the app's `Program` file defines the order in which middleware are invoked on a request with the reverse order for the response. + +You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios, keeping in mind that the order is critical for security, performance, and functionality. + +The following examples demonstrate middleware order for common app scenarios. Each middleware extension method is exposed on through the namespace: + +1. Exception/error handling + * When the app runs in the `Development` environment: + * Developer Exception Page Middleware () reports app runtime errors. + * Database Error Page Middleware () reports database runtime errors. + * When the app runs in the `Production` environment: + * Exception Handler Middleware () catches exceptions thrown in the following middlewares. + * HTTP Strict Transport Security Protocol (HSTS) Middleware () adds the `Strict-Transport-Security` header. +1. HTTPS Redirection Middleware () redirects HTTP requests to HTTPS. +1. Antiforgery Middleware () adds anti-forgery middleware to the pipeline. +1. Static File Middleware (if required, ) returns static files and short-circuits further request processing. +1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR) regulations. +1. Routing Middleware (Razor Pages and MVC only, ) to route requests. +1. Authentication Middleware (Razor Pages and MVC only, ) attempts to authenticate the user before they're allowed access to secure resources. +1. Authorization Middleware (Razor Pages and MVC only, ) authorizes a user to access secure resources. +1. A call to must be placed after calls to and . +1. Session Middleware (Razor Pages and MVC only, ) establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before MVC Middleware. +1. Endpoint Routing Middleware + * to add Razor component endpoints to the request pipeline. + * to add Razor Pages endpoints to the request pipeline. + * to add controller endpoints to the request pipeline. + + +Typical Blazor Web App middleware pipeline: + +```csharp +app.UseWebAssemblyDebugging(); // Development environment with client-side rendering +app.UseMigrationsEndPoint(); // Development environment with ASP.NET Core Identity + +app.UseExceptionHandler("/Error", createScopeForErrors: true); // Non-Development environment +app.UseHsts(); // Non-Development environment with HTTPS protocol + +app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true); + +app.UseHttpsRedirection(); // With HTTPS protocol + +app.UseAntiforgery(); + +app.MapStaticAssets(); + +app.MapRazorComponents(); // With additional extension methods for render modes + +app.MapAdditionalIdentityEndpoints(); // With ASP.NET Core Identity + +app.Run(); +``` + +Typical Razor Pages/MVC middleware pipeline: + +```csharp +app.UseMigrationsEndPoint(); // Development environment with ASP.NET Core Identity + +app.UseExceptionHandler("/Error"); // Non-Development environment +app.UseHsts(); // Non-Development environment with HTTPS protocol + +app.UseHttpsRedirection(); // With HTTPS protocol + +// app.UseCookiePolicy(); +app.UseRouting(); // If not called, runs at the beginning of the pipeline by default +// app.UseRateLimiter(); +// app.UseRequestLocalization(); +// app.UseCors(); + +// app.UseAuthentication(); // Called internally for ASP.NET Core Identity +app.UseAuthorization(); +// app.UseSession(); +// app.UseResponseCompression(); +// app.UseResponseCaching(); + +app.MapStaticAssets(); + +app.MapControllerRoute(...); // For MVC controllers + +app.MapRazorPages(); // For Razor Pages pages + +app.MapControllers(); // With authentication in a Razor Pages app + +app.Run(); +``` + +In the preceding code: + +* CORS Middleware (), Authentication Middleware (), and Authorization Middleware () must appear in the order shown. +* CORS Middleware () must appear before Response Caching Middleware () to add CORS headers on every request to include cached responses. For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). +* Request Localization Middleware () must appear before any middleware that might check the request culture, for example, Static File Middleware (). +* Rate Limiting Middleware () must be called after Routing Middleware () when rate limiting endpoint-specific APIs are used. For example, if the [`[EnableRateLimiting]` attribute](xref:Microsoft.AspNetCore.RateLimiting.EnableRateLimitingAttribute) is used, Rate Limiting Middleware must be called after Routing Middleware. When calling only global limiters, Rate Limiting Middleware can be called before Routing Middleware. + +In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there are multiple valid orderings. In the following order, CPU usage could be reduced by caching the compressed response, but the app might end up caching multiple representations of a resource using different compression algorithms, such as Gzip or Brotli: + +```csharp +app.UseResponseCaching(); +app.UseResponseCompression(); +``` + +Static assets are typically served early in the pipeline so that the app can short-circuit request processing to improve performance. + +Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization occurs after the framework selects a Razor component in a Blazor Web App, a page in a Razor Pages app, or a controller and action in an MVC app. + +## `UseCors` and `UseStaticFiles` order + +The order for calling and depends on the app. For more information, see [`UseCors` and `UseStaticFiles` order](xref:security/cors#usecors-and-usestaticfiles-order). + +## Forwarded Headers Middleware order + +Run Forwarded Headers Middleware before other middleware to ensure that the middleware relying on forwarded headers information can consume the header values for processing. To run Forwarded Headers Middleware after Diagnostics and Error Handling Middleware, see [Forwarded Headers Middleware order](xref:host-and-deploy/proxy-load-balancer#forwarded-headers-middleware-order). + ## Built-in middleware ASP.NET Core ships with the following middleware. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. @@ -495,7 +460,7 @@ Middleware | Description | Order [Endpoint Routing](xref:fundamentals/routing) | Defines and constrains request routes. | Terminal for matching routes. [SPA](xref:Microsoft.AspNetCore.Builder.SpaApplicationBuilderExtensions.UseSpa%2A) | Handles all requests from this point in the middleware chain by returning the default page for the Single Page Application (SPA) | Appears late in the pipeline, so that other middleware for serving static files, such as MVC actions, take precedence. [Session](xref:fundamentals/app-state) | Provides support for managing user sessions. | Before middleware that require Session. -[Static Files](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | Terminal if a request matches a file. +[Static File](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | Terminal if a request matches a file. [URL Rewrite](xref:fundamentals/url-rewriting) | Provides support for rewriting URLs and redirecting requests. | Before middleware that consume the URL. [W3CLogging](xref:fundamentals/w3c-logger/index) | Generates server access logs in the [W3C Extended Log File Format](https://www.w3.org/TR/WD-logfile.html). | At the beginning of the middleware pipeline. [WebSockets](xref:fundamentals/websockets) | Enables the WebSockets protocol. | Before middleware that are required to accept WebSocket requests. diff --git a/aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg b/aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg deleted file mode 100644 index 186e100a3b5d..000000000000 --- a/aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg +++ /dev/null @@ -1,324 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From bf4bce61af1770181773a45094eb59d508750dca Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 15 Jan 2026 12:49:08 -0500 Subject: [PATCH 08/16] Updates --- .../index/_static/middleware-pipeline.svg | 324 ++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg diff --git a/aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg b/aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg new file mode 100644 index 000000000000..186e100a3b5d --- /dev/null +++ b/aspnetcore/fundamentals/middleware/index/_static/middleware-pipeline.svg @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f6c86548bed525642ce727cdcc0ff9e3ba18709b Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 16 Jan 2026 10:54:48 -0500 Subject: [PATCH 09/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 157 ++++++++++++-------- 1 file changed, 94 insertions(+), 63 deletions(-) diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 27f55701a2c4..89dc58fbf830 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -204,35 +204,22 @@ private static void HandleMap2(IApplicationBuilder app) The following table shows the requests and responses using the preceding code. -Request | Response ---------- | ---------------------------------------------------- -`/` | :::no-loc text="Hello from the non-Map delegate."::: -`/map1` | :::no-loc text="Map 1"::: -`/map2` | :::no-loc text="Map 2"::: -`/map3` | :::no-loc text="Hello from the non-Map delegate."::: +Request | Response +--- | --- +`/` | :::no-loc text="Hello from the non-Map delegate."::: +`/map1` | :::no-loc text="Map 1"::: +`/map2` | :::no-loc text="Map 2"::: +`/map3` | :::no-loc text="Hello from the non-Map delegate."::: When is used, the matched path segments are removed from and appended to for each request. - supports nesting, for example: - -```csharp -app.Map("/level1", level1App => { - level1App.Map("/level2a", level2AApp => { - // "/level1/level2a" processing - }); - level1App.Map("/level2b", level2BApp => { - // "/level1/level2b" processing - }); -}); -``` - - can also match multiple segments at once: + can match multiple segments at once: ```csharp var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); -app.Map("/map1/seg1", HandleMultiSeg); +app.Map("/map1/segment1", HandleMultiSeg); app.Run(async context => { @@ -245,11 +232,55 @@ private static void HandleMultiSeg(IApplicationBuilder app) { app.Run(async context => { - await context.Response.WriteAsync("Map 1 - Segment 1"); + await context.Response.WriteAsync("Processing '/map1/segment1'"); }); } ``` +The following table shows the requests and responses using the preceding code. + +Request | Response +--- | --- +`/` | :::no-loc text="Hello from the non-Map delegate."::: +`/map1/segment1` | :::no-loc text="Processing '/map1/segment1'"::: + + supports nesting: + +```csharp +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.Map("/level1", level1App => { + level1App.Map("/level2a", level2AApp => { + app.Run(async context => + { + await context.Response.WriteAsync("Processing '/level1/level2a'"); + }); + }); + level1App.Map("/level2b", level2BApp => { + app.Run(async context => + { + await context.Response.WriteAsync("Processing '/level1/level2b'"); + }); + }); +}); + +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from the non-Map delegate!"); +}); + +app.Run(); +``` + +The following table shows the requests and responses using the preceding code. + +Request | Response +--- | --- +`/` | :::no-loc text="Hello from the non-Map delegate."::: +`/level1/level2a` | :::no-loc text="Processing '/level1/level2a'"::: +`/level1/level2b` | :::no-loc text="Processing '/level1/level2b'"::: + branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable named "`branch`": ```csharp @@ -270,7 +301,7 @@ private static void HandleBranch(IApplicationBuilder app) app.Run(async context => { var branchVer = context.Request.Query["branch"]; - await context.Response.WriteAsync($"Branch used = {branchVer}"); + await context.Response.WriteAsync($"Branch used = '{branchVer}'"); }); } ``` @@ -280,9 +311,9 @@ The following table shows the requests and responses using the previous code: Request | Response --- | --- `/` | :::no-loc text="Hello from the non-Map delegate."::: -`/?branch=main` | :::no-loc text="Branch used = main"::: +`/?branch=main` | :::no-loc text="Branch used = 'main'"::: - also branches the request pipeline based on the result of the given predicate. Unlike when calling , this branch is rejoined to the main pipeline if it doesn't contain a terminal middleware: + can branch the request pipeline based on the result of the given predicate. Unlike when calling , this branch is rejoined to the main pipeline if it doesn't contain a terminal middleware: ```csharp var builder = WebApplication.CreateBuilder(args); @@ -320,7 +351,7 @@ In the preceding example, a response of ":::no-loc text="Hello from the non-Map The order that middleware appears in the app's `Program` file defines the order in which middleware are invoked on a request with the reverse order for the response. -You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios, keeping in mind that the order is critical for security, performance, and functionality. +You have full control over the order of middleware and the ability to add custom middleware for request processing scenarios, keeping in mind that the order of middleware can be critical for security, performance, and functionality. The following examples demonstrate middleware order for common app scenarios. Each middleware extension method is exposed on through the namespace: @@ -336,10 +367,10 @@ The following examples demonstrate middleware order for common app scenarios. Ea 1. Static File Middleware (if required, ) returns static files and short-circuits further request processing. 1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR) regulations. 1. Routing Middleware (Razor Pages and MVC only, ) to route requests. -1. Authentication Middleware (Razor Pages and MVC only, ) attempts to authenticate the user before they're allowed access to secure resources. -1. Authorization Middleware (Razor Pages and MVC only, ) authorizes a user to access secure resources. +1. Authentication Middleware () attempts to authenticate the user before they're allowed access to secure resources. +1. Authorization Middleware () authorizes a user to access secure resources. 1. A call to must be placed after calls to and . -1. Session Middleware (Razor Pages and MVC only, ) establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before MVC Middleware. +1. Session Middleware (Razor Pages and MVC only, ) establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before Razor Pages/MVC Middleware. 1. Endpoint Routing Middleware * to add Razor component endpoints to the request pipeline. * to add Razor Pages endpoints to the request pipeline. @@ -419,7 +450,7 @@ app.UseResponseCompression(); Static assets are typically served early in the pipeline so that the app can short-circuit request processing to improve performance. -Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization occurs after the framework selects a Razor component in a Blazor Web App, a page in a Razor Pages app, or a controller and action in an MVC app. +Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization occurs after the framework selects a page in a Razor Pages app or a controller and action in an MVC app. ## `UseCors` and `UseStaticFiles` order @@ -431,39 +462,39 @@ Run Forwarded Headers Middleware before other middleware to ensure that the midd ## Built-in middleware -ASP.NET Core ships with the following middleware. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. - -Middleware | Description | Order ---- | --- | --- -[Antiforgery](xref:security/anti-request-forgery) | Provides anti-request-forgery support. | After authentication and authorization, before endpoints. -[Authentication](xref:security/authentication/identity) | Provides authentication support. | Before `HttpContext.User` is needed. Terminal for OAuth callbacks. -[Authorization](xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A) | Provides authorization support. | Immediately after the Authentication Middleware. -[Cookie Policy](xref:security/gdpr) | Tracks consent from users for storing personal information and enforces minimum standards for cookie fields, such as `secure` and `SameSite`. | Before middleware that issues cookies. Examples: Authentication, Session, MVC (TempData). -[CORS](xref:security/cors) | Configures Cross-Origin Resource Sharing. | Before middleware that use CORS. must go before . For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). -[DeveloperExceptionPage](xref:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware) | Generates a page with error information that is intended for use only in the `Development` environment. | Before middleware that generate errors. The project templates automatically register this middleware as the first middleware in the pipeline when the environment is `Development`. -[Diagnostics](xref:fundamentals/error-handling) | Several separate middlewares that provide a developer exception page, exception handling, status code pages, and the default web page for new apps. | Before middleware that generate errors. Terminal for exceptions or serving the default web page for new apps. -[Forwarded Headers](xref:host-and-deploy/proxy-load-balancer) | Forwards proxied headers onto the current request. | Before middleware that consume the updated fields. Examples: scheme, host, client IP, method. -[Health Check](xref:host-and-deploy/health-checks) | Checks the health of an ASP.NET Core app and its dependencies, such as checking database availability. | Terminal if a request matches a health check endpoint. -[Header Propagation](xref:fundamentals/http-requests#header-propagation-middleware) | Propagates HTTP headers from the incoming request to the outgoing HTTP Client requests. -[HTTP Logging](xref:fundamentals/http-logging/index) | Logs HTTP Requests and Responses. | At the beginning of the middleware pipeline. -[HTTP Method Override](xref:Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions) | Allows an incoming POST request to override the method. | Before middleware that consume the updated method. -[HTTPS Redirection](xref:security/enforcing-ssl#require-https) | Redirect all HTTP requests to HTTPS. | Before middleware that consume the URL. -[HTTP Strict Transport Security (HSTS)](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) | Security enhancement middleware that adds a special response header. | Before responses are sent and after middleware that modify requests. Examples: Forwarded Headers, URL Rewriting. -[MVC](xref:mvc/overview) | Processes requests with MVC/Razor Pages. | Terminal if a request matches a route. -[OWIN](xref:fundamentals/owin) | Interop with OWIN-based apps, servers, and middleware. | Terminal if the OWIN Middleware fully processes the request. -[Output Caching](xref:performance/caching/output) | Provides support for caching responses based on configuration. | Before middleware that require caching. must come before `UseOutputCaching`. must come before `UseOutputCaching`. -[Response Caching](xref:performance/caching/middleware) | Provides support for caching responses. This requires client participation to work. Use output caching for complete server control. | Before middleware that require caching. must come before . Response caching isn't typically beneficial for UI apps, such as Razor Pages, because browsers generally set request headers that prevent caching. [Output caching](xref:performance/caching/output) benefits UI apps. -[Request Decompression](xref:fundamentals/middleware/request-decompression) | Provides support for decompressing requests. | Before middleware that read the request body. -[Response Compression](xref:performance/response-compression) | Provides support for compressing responses. | Before middleware that require compression. -[Request Localization](xref:fundamentals/localization) | Provides localization support. | Before localization sensitive middleware. Must appear after Routing Middleware when using . -[Request Timeouts](xref:performance/timeouts) | Provides support for configuring request timeouts, global and per endpoint. | must come after , , and . -[Endpoint Routing](xref:fundamentals/routing) | Defines and constrains request routes. | Terminal for matching routes. -[SPA](xref:Microsoft.AspNetCore.Builder.SpaApplicationBuilderExtensions.UseSpa%2A) | Handles all requests from this point in the middleware chain by returning the default page for the Single Page Application (SPA) | Appears late in the pipeline, so that other middleware for serving static files, such as MVC actions, take precedence. -[Session](xref:fundamentals/app-state) | Provides support for managing user sessions. | Before middleware that require Session. -[Static File](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | Terminal if a request matches a file. -[URL Rewrite](xref:fundamentals/url-rewriting) | Provides support for rewriting URLs and redirecting requests. | Before middleware that consume the URL. -[W3CLogging](xref:fundamentals/w3c-logger/index) | Generates server access logs in the [W3C Extended Log File Format](https://www.w3.org/TR/WD-logfile.html). | At the beginning of the middleware pipeline. -[WebSockets](xref:fundamentals/websockets) | Enables the WebSockets protocol. | Before middleware that are required to accept WebSocket requests. +ASP.NET Core ships with the following middleware. The *UI stack* column indicates the typical UI stack where the middleware is used [All, Blazor (B), Razor Pages and MVC (RP/MVC)]. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. + +Middleware | Description | UI stack | Order +--- | --- | --- | --- +[Antiforgery](xref:security/anti-request-forgery) | Provides anti-request-forgery support. | All | After authentication and authorization, before endpoints. +[Authentication](xref:security/authentication/identity) | Provides authentication support. | RP/MVC | Before `HttpContext.User` is needed. Terminal for OAuth callbacks. +[Authorization](xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A) | Provides authorization support. | | Immediately after the Authentication Middleware. +[Cookie Policy](xref:security/gdpr) | Tracks consent from users for storing personal information and enforces minimum standards for cookie fields, such as `secure` and `SameSite`. | | Before middleware that issues cookies. Examples: Authentication, Session, MVC (TempData). +[CORS](xref:security/cors) | Configures Cross-Origin Resource Sharing. | | Before middleware that use CORS. must go before . For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). +[DeveloperExceptionPage](xref:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware) | Generates a page with error information that is intended for use only in the `Development` environment. | | Before middleware that generate errors. The project templates automatically register this middleware as the first middleware in the pipeline when the environment is `Development`. +[Diagnostics](xref:fundamentals/error-handling) | Several separate middlewares that provide a developer exception page, exception handling, status code pages, and the default web page for new apps. | | Before middleware that generate errors. Terminal for exceptions or serving the default web page for new apps. +[Forwarded Headers](xref:host-and-deploy/proxy-load-balancer) | Forwards proxied headers onto the current request. | | Before middleware that consume the updated fields. Examples: scheme, host, client IP, method. +[Health Check](xref:host-and-deploy/health-checks) | Checks the health of an ASP.NET Core app and its dependencies, such as checking database availability. | | Terminal if a request matches a health check endpoint. +[Header Propagation](xref:fundamentals/http-requests#header-propagation-middleware) | Propagates HTTP headers from the incoming request to the outgoing HTTP Client requests. | | +[HTTP Logging](xref:fundamentals/http-logging/index) | Logs HTTP Requests and Responses. | | At the beginning of the middleware pipeline. +[HTTP Method Override](xref:Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions) | Allows an incoming POST request to override the method. | | Before middleware that consume the updated method. +[HTTPS Redirection](xref:security/enforcing-ssl#require-https) | Redirect all HTTP requests to HTTPS. | | Before middleware that consume the URL. +[HTTP Strict Transport Security (HSTS)](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) | Security enhancement middleware that adds a special response header. | | Before responses are sent and after middleware that modify requests. Examples: Forwarded Headers, URL Rewriting. +[MVC](xref:mvc/overview) | Processes requests with MVC/Razor Pages. | | Terminal if a request matches a route. +[OWIN](xref:fundamentals/owin) | Interop with OWIN-based apps, servers, and middleware. | | Terminal if the OWIN Middleware fully processes the request. +[Output Caching](xref:performance/caching/output) | Provides support for caching responses based on configuration. | | Before middleware that require caching. must come before `UseOutputCaching`. must come before `UseOutputCaching`. +[Response Caching](xref:performance/caching/middleware) | Provides support for caching responses. This requires client participation to work. Use output caching for complete server control. | | Before middleware that require caching. must come before . Response caching isn't typically beneficial for UI apps, such as Razor Pages, because browsers generally set request headers that prevent caching. [Output caching](xref:performance/caching/output) benefits UI apps. +[Request Decompression](xref:fundamentals/middleware/request-decompression) | Provides support for decompressing requests. | | Before middleware that read the request body. +[Response Compression](xref:performance/response-compression) | Provides support for compressing responses. | | Before middleware that require compression. +[Request Localization](xref:fundamentals/localization) | Provides localization support. | | Before localization sensitive middleware. Must appear after Routing Middleware when using . +[Request Timeouts](xref:performance/timeouts) | Provides support for configuring request timeouts, global and per endpoint. | | must come after , , and . +[Endpoint Routing](xref:fundamentals/routing) | Defines and constrains request routes. | | Terminal for matching routes. +[SPA](xref:Microsoft.AspNetCore.Builder.SpaApplicationBuilderExtensions.UseSpa%2A) | Handles all requests from this point in the middleware chain by returning the default page for the Single Page Application (SPA) | | Appears late in the pipeline, so that other middleware for serving static files, such as MVC actions, take precedence. +[Session](xref:fundamentals/app-state) | Provides support for managing user sessions. | | Before middleware that require Session. +[Static File](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | | Terminal if a request matches a file. +[URL Rewrite](xref:fundamentals/url-rewriting) | Provides support for rewriting URLs and redirecting requests. | | Before middleware that consume the URL. +[W3CLogging](xref:fundamentals/w3c-logger/index) | Generates server access logs in the [W3C Extended Log File Format](https://www.w3.org/TR/WD-logfile.html). | | At the beginning of the middleware pipeline. +[WebSockets](xref:fundamentals/websockets) | Enables the WebSockets protocol. | | Before middleware that are required to accept WebSocket requests. ## Additional resources From 2df63d6e94e73d1f516c0b77db7c1f51fc63fb5e Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 16 Jan 2026 12:29:20 -0500 Subject: [PATCH 10/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 70 +++++++++++-------- .../performance/response-compression.md | 3 +- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 89dc58fbf830..832185a1b15c 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -462,39 +462,51 @@ Run Forwarded Headers Middleware before other middleware to ensure that the midd ## Built-in middleware -ASP.NET Core ships with the following middleware. The *UI stack* column indicates the typical UI stack where the middleware is used [All, Blazor (B), Razor Pages and MVC (RP/MVC)]. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. +ASP.NET Core ships with the following middleware. The *UI stack* column indicates the typical UI stack where the middleware is used [All, Blazor Web App (BWA), Razor Pages and MVC (RP/MVC)]. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. + + Middleware | Description | UI stack | Order --- | --- | --- | --- [Antiforgery](xref:security/anti-request-forgery) | Provides anti-request-forgery support. | All | After authentication and authorization, before endpoints. -[Authentication](xref:security/authentication/identity) | Provides authentication support. | RP/MVC | Before `HttpContext.User` is needed. Terminal for OAuth callbacks. -[Authorization](xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A) | Provides authorization support. | | Immediately after the Authentication Middleware. -[Cookie Policy](xref:security/gdpr) | Tracks consent from users for storing personal information and enforces minimum standards for cookie fields, such as `secure` and `SameSite`. | | Before middleware that issues cookies. Examples: Authentication, Session, MVC (TempData). -[CORS](xref:security/cors) | Configures Cross-Origin Resource Sharing. | | Before middleware that use CORS. must go before . For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). -[DeveloperExceptionPage](xref:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware) | Generates a page with error information that is intended for use only in the `Development` environment. | | Before middleware that generate errors. The project templates automatically register this middleware as the first middleware in the pipeline when the environment is `Development`. -[Diagnostics](xref:fundamentals/error-handling) | Several separate middlewares that provide a developer exception page, exception handling, status code pages, and the default web page for new apps. | | Before middleware that generate errors. Terminal for exceptions or serving the default web page for new apps. -[Forwarded Headers](xref:host-and-deploy/proxy-load-balancer) | Forwards proxied headers onto the current request. | | Before middleware that consume the updated fields. Examples: scheme, host, client IP, method. -[Health Check](xref:host-and-deploy/health-checks) | Checks the health of an ASP.NET Core app and its dependencies, such as checking database availability. | | Terminal if a request matches a health check endpoint. -[Header Propagation](xref:fundamentals/http-requests#header-propagation-middleware) | Propagates HTTP headers from the incoming request to the outgoing HTTP Client requests. | | -[HTTP Logging](xref:fundamentals/http-logging/index) | Logs HTTP Requests and Responses. | | At the beginning of the middleware pipeline. -[HTTP Method Override](xref:Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions) | Allows an incoming POST request to override the method. | | Before middleware that consume the updated method. -[HTTPS Redirection](xref:security/enforcing-ssl#require-https) | Redirect all HTTP requests to HTTPS. | | Before middleware that consume the URL. -[HTTP Strict Transport Security (HSTS)](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) | Security enhancement middleware that adds a special response header. | | Before responses are sent and after middleware that modify requests. Examples: Forwarded Headers, URL Rewriting. -[MVC](xref:mvc/overview) | Processes requests with MVC/Razor Pages. | | Terminal if a request matches a route. -[OWIN](xref:fundamentals/owin) | Interop with OWIN-based apps, servers, and middleware. | | Terminal if the OWIN Middleware fully processes the request. -[Output Caching](xref:performance/caching/output) | Provides support for caching responses based on configuration. | | Before middleware that require caching. must come before `UseOutputCaching`. must come before `UseOutputCaching`. -[Response Caching](xref:performance/caching/middleware) | Provides support for caching responses. This requires client participation to work. Use output caching for complete server control. | | Before middleware that require caching. must come before . Response caching isn't typically beneficial for UI apps, such as Razor Pages, because browsers generally set request headers that prevent caching. [Output caching](xref:performance/caching/output) benefits UI apps. -[Request Decompression](xref:fundamentals/middleware/request-decompression) | Provides support for decompressing requests. | | Before middleware that read the request body. -[Response Compression](xref:performance/response-compression) | Provides support for compressing responses. | | Before middleware that require compression. -[Request Localization](xref:fundamentals/localization) | Provides localization support. | | Before localization sensitive middleware. Must appear after Routing Middleware when using . -[Request Timeouts](xref:performance/timeouts) | Provides support for configuring request timeouts, global and per endpoint. | | must come after , , and . -[Endpoint Routing](xref:fundamentals/routing) | Defines and constrains request routes. | | Terminal for matching routes. -[SPA](xref:Microsoft.AspNetCore.Builder.SpaApplicationBuilderExtensions.UseSpa%2A) | Handles all requests from this point in the middleware chain by returning the default page for the Single Page Application (SPA) | | Appears late in the pipeline, so that other middleware for serving static files, such as MVC actions, take precedence. -[Session](xref:fundamentals/app-state) | Provides support for managing user sessions. | | Before middleware that require Session. -[Static File](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | | Terminal if a request matches a file. -[URL Rewrite](xref:fundamentals/url-rewriting) | Provides support for rewriting URLs and redirecting requests. | | Before middleware that consume the URL. -[W3CLogging](xref:fundamentals/w3c-logger/index) | Generates server access logs in the [W3C Extended Log File Format](https://www.w3.org/TR/WD-logfile.html). | | At the beginning of the middleware pipeline. -[WebSockets](xref:fundamentals/websockets) | Enables the WebSockets protocol. | | Before middleware that are required to accept WebSocket requests. +[Authentication](xref:security/authentication/identity) | Provides authentication support. | All | Before `HttpContext.User` is needed. Terminal for OAuth callbacks. +[Authorization](xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A) | Provides authorization support. | All | Immediately after the Authentication Middleware. +[Cookie Policy](xref:security/gdpr) | Tracks consent from users for storing personal information and enforces minimum standards for cookie fields, such as `secure` and `SameSite`. | All | Before middleware that issues cookies. Examples: Authentication, Session, MVC (TempData). +[CORS](xref:security/cors) | Configures Cross-Origin Resource Sharing. | All | Before middleware that use CORS. must go before . For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). +[Developer Exception Page](xref:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware) | Generates a page with error information that is intended for use only in the `Development` environment. | All | Before middleware that generate errors. The project templates automatically register this middleware as the first middleware in the pipeline when the environment is `Development`. +[Diagnostics](xref:fundamentals/error-handling) | Several separate middlewares that provide a developer exception page, exception handling, status code pages, and the default web page for new apps. | All | Before middleware that generate errors. Terminal for exceptions or serving the default web page for new apps. +[Forwarded Headers](xref:host-and-deploy/proxy-load-balancer) | Forwards proxied headers onto the current request. | All | Before middleware that consume the updated fields. Examples: scheme, host, client IP, method. +[Health Check](xref:host-and-deploy/health-checks) | Checks the health of an ASP.NET Core app and its dependencies, such as checking database availability. | All | Terminal if a request matches a health check endpoint. +[Header Propagation](xref:fundamentals/http-requests#header-propagation-middleware) | Propagates HTTP headers from the incoming request to the outgoing HTTP Client requests. | +All | +[HTTP Logging](xref:fundamentals/http-logging/index) | Logs HTTP Requests and Responses. | All | At the beginning of the middleware pipeline. +[HTTP Method Override](xref:Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions) | Allows an incoming POST request to override the method. | All | Before middleware that consume the updated method. +[HTTPS Redirection](xref:security/enforcing-ssl#require-https) | Redirect all HTTP requests to HTTPS. | All | Before middleware that consume the URL. +[HTTP Strict Transport Security (HSTS)](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) | Security enhancement middleware that adds a special response header. | All | Before responses are sent and after middleware that modify requests. Examples: Forwarded Headers, URL Rewriting. +[MVC](xref:mvc/overview) | Processes requests with MVC/Razor Pages. | RP/MVC | Terminal if a request matches a route. +[OWIN](xref:fundamentals/owin) | Interop with OWIN-based apps, servers, and middleware. | RP/MVC | Terminal if the OWIN Middleware fully processes the request. +[Output Caching](xref:performance/caching/output) | Provides support for caching responses based on configuration. | RP/MVC | Before middleware that require caching. must come before `UseOutputCaching`. must come before `UseOutputCaching`. +[Response Caching](xref:performance/caching/middleware) | Provides support for caching responses. This requires client participation to work. Use output caching for complete server control. | RP/MVC | Before middleware that require caching. must come before . Response caching isn't typically beneficial for UI apps, such as Razor Pages, because browsers generally set request headers that prevent caching. [Output caching](xref:performance/caching/output) benefits UI apps. +[Request Decompression](xref:fundamentals/middleware/request-decompression) | Provides support for decompressing requests. | All | Before middleware that read the request body. +[Response Compression](xref:performance/response-compression) | Provides support for compressing responses. | All | Before middleware that require compression. +[Request Localization](xref:fundamentals/localization) | Provides localization support. | All | Before localization sensitive middleware. Must appear after Routing Middleware when using . +[Request Timeouts](xref:performance/timeouts) | Provides support for configuring request timeouts, global and per endpoint. | All | must come after , , and . +[Endpoint Routing](xref:fundamentals/routing) | Defines and constrains request routes. | All | Terminal for matching routes. +[SPA](xref:Microsoft.AspNetCore.Builder.SpaApplicationBuilderExtensions.UseSpa%2A) | Handles all requests from this point in the middleware chain by returning the default page for the Single Page Application (SPA) | All | Appears late in the pipeline, so that other middleware for serving static files, such as MVC actions, take precedence. +[Session](xref:fundamentals/app-state) | Provides support for managing user sessions. | RP/MVC | Before middleware that require Session. +[Static File](xref:fundamentals/static-files) | Provides support for serving static files and directory browsing. | All | Terminal if a request matches a file. +[URL Rewrite](xref:fundamentals/url-rewriting) | Provides support for rewriting URLs and redirecting requests. | All | Before middleware that consume the URL. +[W3C Logging](xref:fundamentals/w3c-logger/index) | Generates server access logs in the [W3C Extended Log File Format](https://www.w3.org/TR/WD-logfile.html). | All | At the beginning of the middleware pipeline. +[Blazor WebAssembly Debugging](xref:blazor/debug) | Debugging Blazor Web Apps that adopt client-side rendering (CSR) inside Chromium developer tools. | BWA | At the beginning of the middleware pipeline. +[WebSockets](xref:fundamentals/websockets) | Enables the WebSockets protocol. | All | Before middleware that are required to accept WebSocket requests. ## Additional resources diff --git a/aspnetcore/performance/response-compression.md b/aspnetcore/performance/response-compression.md index ef25f73e95a8..347a2022d8fd 100644 --- a/aspnetcore/performance/response-compression.md +++ b/aspnetcore/performance/response-compression.md @@ -18,8 +18,7 @@ Network bandwidth is a limited resource. Reducing the size of the response usual ## Compression with HTTPS -Compressed responses over secure connections can be controlled with the option, which is disabled by default because of the security risk. Using compression with dynamically generated pages can expose the app to [CRIME](https://wikipedia.org/wiki/CRIME_(security_exploit)) and [BREACH](https://wikipedia.org/wiki/BREACH_(security_exploit)) attacks. CRIME and BREACH attacks can be - mitigated in ASP.NET Core with antiforgery tokens. For more information, see . For information on mitigating BREACH attacks, see [mitigations](http://www.breachattack.com/#mitigations) at http://www.breachattack.com/ +Compressed responses over secure connections can be controlled with the option, which is disabled by default because of the security risk. Using compression with dynamically generated pages can expose the app to [CRIME](https://wikipedia.org/wiki/CRIME_(security_exploit)) and [BREACH](https://wikipedia.org/wiki/BREACH_(security_exploit)) attacks. CRIME and BREACH attacks can be mitigated in ASP.NET Core with antiforgery tokens. For more information, see . For information on mitigating BREACH attacks, see [mitigations](http://www.breachattack.com/#mitigations) at http://www.breachattack.com/ Even when `EnableForHttps` is disabled in the app, IIS, IIS Express, and [Azure App Service](xref:host-and-deploy/azure-iis-errors-reference) can apply gzip at the IIS web server. When reviewing response headers, take note of the [Server](https://developer.mozilla.org/docs/Web/HTTP/Headers/Server) value. An unexpected `content-encoding` response header value may be the result of the web server and not the ASP.NET Core app configuration. From 61d9cfcb86e6f5e69b007f0b8a7af59e954cf7a8 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 16 Jan 2026 12:30:29 -0500 Subject: [PATCH 11/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 832185a1b15c..ff6bd7f581b1 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -6,7 +6,7 @@ description: Learn about ASP.NET Core middleware and the request pipeline. monikerRange: '>= aspnetcore-3.0' ms.author: tdykstra ms.custom: mvc -ms.date: 01/15/2026 +ms.date: 01/16/2026 uid: fundamentals/middleware/index --- # ASP.NET Core Middleware @@ -26,7 +26,7 @@ Request delegates are configured using explains the difference between request pipelines in ASP.NET Core and ASP.NET 4.x and provides additional middleware samples. -## The role of middleware by app type +## Role of middleware by app type Blazor Web Apps, Razor Pages, and MVC process browser requests on the server with middleware. The guidance in this article applies to these types of apps. From a9d1dbffc355dd7b356d6d90a5271cf06077da27 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 20 Jan 2026 07:28:44 -0500 Subject: [PATCH 12/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 56 +++++++++++---------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index ff6bd7f581b1..b18ae475282b 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -6,7 +6,7 @@ description: Learn about ASP.NET Core middleware and the request pipeline. monikerRange: '>= aspnetcore-3.0' ms.author: tdykstra ms.custom: mvc -ms.date: 01/16/2026 +ms.date: 01/20/2026 uid: fundamentals/middleware/index --- # ASP.NET Core Middleware @@ -22,9 +22,9 @@ Middleware is software that's assembled into an app pipeline to handle requests Request delegates are used to build the request pipeline. The request delegates handle each HTTP request. -Request delegates are configured using , , and extension methods. An individual request delegate can be specified inline as an anonymous method (called inline middleware), or it can be defined in a reusable class. These reusable classes and inline anonymous methods are *middleware*, also called *middleware components* (not to be confused with [Razor components](xref:blazor/index#components) or [View components](xref:mvc/views/view-components)). Each middleware in the request pipeline is responsible for invoking the next middleware in the pipeline or short-circuiting the pipeline. When a middleware short-circuits, it's called a *terminal middleware* because it prevents further middleware from processing the request. +Request delegates are configured using , , and extension methods. An individual request delegate can be specified inline as an anonymous method (called inline middleware) or defined in a reusable class. These inline anonymous methods or reusable classes are called *middleware* or *middleware components*. Each middleware in the request pipeline is responsible for invoking the next middleware in the pipeline or short-circuiting the pipeline. When a middleware short-circuits, it's called a *terminal middleware* because it prevents further middleware from processing the request. - explains the difference between request pipelines in ASP.NET Core and ASP.NET 4.x and provides additional middleware samples. +For more information on the difference between request pipelines in ASP.NET Core and ASP.NET 4.x with additional middleware samples, see . ## Role of middleware by app type @@ -34,7 +34,7 @@ Standalone Blazor WebAssembly apps run entirely on the client and don't process ## Middleware code analysis -ASP.NET Core includes many compiler platform analyzers that inspect application code for quality. For more information, see . +For more information on ASP.NET Core's compiler platform analyzers that inspect app code for quality, see . ## Create a middleware pipeline with `WebApplication` @@ -47,12 +47,12 @@ Each delegate can perform operations before and after the next delegate. Excepti > [!NOTE] > To experiment locally with the code examples in this section, create an ASP.NET Core app using the **ASP.NET Core Empty** project template. If using the .NET CLI, the template short name is `web` (`dotnet new web`). -The simplest possible ASP.NET Core app calls to set up a single terminal middleware request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. +The simplest ASP.NET Core app calls to set up a single terminal middleware as an anonymous function request delegate to handle requests without a request pipeline. In the following example: * The call to is invoked on every request and writes ":::no-loc text="Hello world!":::" to the response. -* The call to runs the app and blocks the calling thread until host shutdown. +* The call to at the end of the code block runs the app and blocks the calling thread until host shutdown. ```csharp var builder = WebApplication.CreateBuilder(args); @@ -74,9 +74,12 @@ Chain multiple request delegates together with calls, each writing to the console where work can be performed to write to the response (`context.Response`, ) and where work can be performed that doesn't write to the response after the `next` parameter is invoked. +* Two calls, each writing to the console: + * Where work can be performed that can write to the response (`context.Response`, ). + * Where work can be performed that doesn't write to the response after the `next` parameter is invoked. * A terminal request delegate with a call to that writes ":::no-loc text="Hello world!":::" to the response. * A final call, which never executes because it follows the terminal request delegate. +* A call to at the end of the code block to run the app and block the calling thread until host shutdown. ```csharp var builder = WebApplication.CreateBuilder(args); @@ -123,12 +126,12 @@ In the app's console window when the app is run: When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the terminal middleware still processes code after their `next.Invoke` statements. -Don't call `next.Invoke` during or after the response has been sent to the client. After an has started, changes result in an exception. For example, [setting headers or a response status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started) after the response starts. Writing to the response body after calling `next` may: +Don't call `next.Invoke` during or after the response is sent to the client. After an is started, changes result in an exception. For example, [setting headers or a response status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started) after the response starts. Writing to the response body after calling `next` may: * Cause a protocol violation, such as writing more bytes to the response than the stated response's content length (`Content-Length` header value). * Corrupt the body format, such as writing an HTML footer to a CSS file. -Call to determine if headers have been sent or the body has been written to. +To determine if the response has started, check the value of . For more information, see [Short-circuit middleware after routing](xref:fundamentals/routing#short-circuit-middleware-after-routing). @@ -163,7 +166,7 @@ app.Use(async (context, next) => }); ``` -If you don't plan to call `next.Invoke` because your goal is to terminate the pipeline, don't call this extension method. Use a [`Run` delegate](#run-delegate) instead. +If you don't plan to call `next.Invoke` because your goal is to terminate the pipeline, use a [`Run` delegate](#run-delegate) instead of calling this extension method. ## Branch the middleware pipeline @@ -219,7 +222,7 @@ When is used, the match var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); -app.Map("/map1/segment1", HandleMultiSeg); +app.Map("/map1/segment1", HandleMultipleSegments); app.Run(async context => { @@ -228,7 +231,7 @@ app.Run(async context => app.Run(); -private static void HandleMultiSeg(IApplicationBuilder app) +private static void HandleMultipleSegments(IApplicationBuilder app) { app.Run(async context => { @@ -306,14 +309,14 @@ private static void HandleBranch(IApplicationBuilder app) } ``` -The following table shows the requests and responses using the previous code: +The following table shows the requests and responses using the preceding code. Request | Response --- | --- `/` | :::no-loc text="Hello from the non-Map delegate."::: `/?branch=main` | :::no-loc text="Branch used = 'main'"::: - can branch the request pipeline based on the result of the given predicate. Unlike when calling , this branch is rejoined to the main pipeline if it doesn't contain a terminal middleware: + can branch the request pipeline based on the result of the given predicate. Unlike , the branch is rejoined to the main pipeline if it doesn't contain a terminal middleware: ```csharp var builder = WebApplication.CreateBuilder(args); @@ -363,13 +366,12 @@ The following examples demonstrate middleware order for common app scenarios. Ea * Exception Handler Middleware () catches exceptions thrown in the following middlewares. * HTTP Strict Transport Security Protocol (HSTS) Middleware () adds the `Strict-Transport-Security` header. 1. HTTPS Redirection Middleware () redirects HTTP requests to HTTPS. -1. Antiforgery Middleware () adds anti-forgery middleware to the pipeline. 1. Static File Middleware (if required, ) returns static files and short-circuits further request processing. -1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR) regulations. -1. Routing Middleware (Razor Pages and MVC only, ) to route requests. +1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR). +1. Routing Middleware () to route requests. 1. Authentication Middleware () attempts to authenticate the user before they're allowed access to secure resources. 1. Authorization Middleware () authorizes a user to access secure resources. -1. A call to must be placed after calls to and . +1. Antiforgery Middleware () adds antiforgery middleware to the pipeline must be placed after calls to and . 1. Session Middleware (Razor Pages and MVC only, ) establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before Razor Pages/MVC Middleware. 1. Endpoint Routing Middleware * to add Razor component endpoints to the request pipeline. @@ -437,11 +439,11 @@ app.Run(); In the preceding code: * CORS Middleware (), Authentication Middleware (), and Authorization Middleware () must appear in the order shown. -* CORS Middleware () must appear before Response Caching Middleware () to add CORS headers on every request to include cached responses. For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). +* CORS Middleware () must appear before Response Caching Middleware () to add CORS headers on every request, including cached responses. For more information, see [It is not clear that UseCORS must come before UseResponseCaching (`dotnet/aspnetcore` #23218](https://github.com/dotnet/aspnetcore/issues/23218). * Request Localization Middleware () must appear before any middleware that might check the request culture, for example, Static File Middleware (). * Rate Limiting Middleware () must be called after Routing Middleware () when rate limiting endpoint-specific APIs are used. For example, if the [`[EnableRateLimiting]` attribute](xref:Microsoft.AspNetCore.RateLimiting.EnableRateLimitingAttribute) is used, Rate Limiting Middleware must be called after Routing Middleware. When calling only global limiters, Rate Limiting Middleware can be called before Routing Middleware. -In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there are multiple valid orderings. In the following order, CPU usage could be reduced by caching the compressed response, but the app might end up caching multiple representations of a resource using different compression algorithms, such as Gzip or Brotli: +In some scenarios, middleware has different ordering. For example, caching and compression ordering depends on the app's specification. In the following order, CPU usage might be reduced by caching the compressed response, but the app might end up caching multiple representations of a resource using different compression algorithms, such as Gzip or Brotli: ```csharp app.UseResponseCaching(); @@ -450,11 +452,11 @@ app.UseResponseCompression(); Static assets are typically served early in the pipeline so that the app can short-circuit request processing to improve performance. -Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization occurs after the framework selects a page in a Razor Pages app or a controller and action in an MVC app. +Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization occurs after the framework selects a Razor component in a Blazor Web App, a page in a Razor Pages app, or a controller and action in an MVC app. ## `UseCors` and `UseStaticFiles` order -The order for calling and depends on the app. For more information, see [`UseCors` and `UseStaticFiles` order](xref:security/cors#usecors-and-usestaticfiles-order). +For more information on ordering and , see . ## Forwarded Headers Middleware order @@ -464,7 +466,7 @@ Run Forwarded Headers Middleware before other middleware to ensure that the midd ASP.NET Core ships with the following middleware. The *UI stack* column indicates the typical UI stack where the middleware is used [All, Blazor Web App (BWA), Razor Pages and MVC (RP/MVC)]. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. - - - - -Use the non-allocating† extension method for a performance benefit: - -* Requires passing the to `next`. -* Saves two internal per-request allocations that are normally required when using the overload that doesn't pass the to `next`. - -> [!NOTE] -> †*Non-allocating* means that the framework avoids creating objects in memory during execution that must be disposed later. - -```csharp -app.Use(async (context, next) => -{ - Console.WriteLine("Work that can write to the response."); - await next.Invoke(context); - Console.WriteLine("Work that doesn't write to the response."); -}); -``` - -If you don't plan to call `next.Invoke` because your goal is to terminate the pipeline, use a [`Run` delegate](#run-delegate) instead of calling this extension method. - ## Branch the middleware pipeline extensions are used as a convention to branch the request processing pipeline. branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. @@ -342,7 +315,7 @@ private void HandleBranchAndRejoin(IApplicationBuilder app) logger.LogInformation("Branch used = {branchVer}", branchVer); Console.WriteLine("Work that can write to the response."); - await next.Invoke(); + await next.Invoke(context); Console.WriteLine("Work that doesn't write to the response."); }); } diff --git a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md index 8742af58d63e..dae8f84cc908 100644 --- a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md +++ b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md @@ -49,12 +49,12 @@ Chain multiple request delegates together with { // Do work that can write to the Response. - await next.Invoke(); + await next.Invoke(context); // Do logging or other work that doesn't write to the Response. }); ``` -When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. +*Short-circuiting* the request pipeline is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the terminal middleware still processes code after their `next.Invoke` statements. If you don't plan to call `next.Invoke` because your goal is to terminate the pipeline, use a [`Run` delegate](#run-delegate) instead of calling the extension method. > [!WARNING] > Don't call `next.Invoke` after the response has been sent to the client. Changes to after the response has started throw an exception. For example, [setting headers and a status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started). Writing to the response body after calling `next`: @@ -75,17 +75,6 @@ app.Run(async context => In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. -### Prefer app.Use overload that requires passing the context to next - - - -The non-allocating [app.Use](xref:Microsoft.AspNetCore.Builder.IApplicationBuilder.Use%2A) extension method: - -* Requires passing the context to `next`. -* Saves two internal per-request allocations that are required when using the other overload. - -For more information, see [this GitHub issue](https://github.com/dotnet/aspnetcore/pull/31784). - ## Middleware order @@ -492,12 +481,12 @@ Chain multiple request delegates together with { // Do work that can write to the Response. - await next.Invoke(); + await next.Invoke(context); // Do logging or other work that doesn't write to the Response. }); ``` -When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. +*Short-circuiting* the request pipeline is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the terminal middleware still processes code after their `next.Invoke` statements. If you don't plan to call `next.Invoke` because your goal is to terminate the pipeline, use a [`Run` delegate](#run-delegate) instead of calling the extension method. > [!WARNING] > Don't call `next.Invoke` after the response has been sent to the client. Changes to after the response has started throw an exception. For example, [setting headers and a status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started). Writing to the response body after calling `next`: @@ -518,17 +507,6 @@ app.Run(async context => In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. -### Prefer app.Use overload that requires passing the context to next - - - -The non-allocating [app.Use](xref:Microsoft.AspNetCore.Builder.IApplicationBuilder.Use%2A) extension method: - -* Requires passing the context to `next`. -* Saves two internal per-request allocations that are required when using the other overload. - -For more information, see [this GitHub issue](https://github.com/dotnet/aspnetcore/pull/31784). - ## Middleware order From fd729352ff11d4819b42f5726cddf13183d07cd6 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 23 Jan 2026 07:49:17 -0500 Subject: [PATCH 14/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 4 ++-- .../fundamentals/middleware/index/includes/index3-7.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 6f417ce7572e..250d64d8183f 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -305,14 +305,14 @@ app.Run(async context => app.Run(); -private void HandleBranchAndRejoin(IApplicationBuilder app) +void HandleBranchAndRejoin(IApplicationBuilder app) { var logger = app.ApplicationServices.GetRequiredService>(); app.Use(async (context, next) => { var branchVer = context.Request.Query["branch"]; - logger.LogInformation("Branch used = {branchVer}", branchVer); + logger.LogInformation("Branch used = {branchVer}", branchVer.ToString()); Console.WriteLine("Work that can write to the response."); await next.Invoke(context); diff --git a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md index dae8f84cc908..bd0a082b663a 100644 --- a/aspnetcore/fundamentals/middleware/index/includes/index3-7.md +++ b/aspnetcore/fundamentals/middleware/index/includes/index3-7.md @@ -377,7 +377,7 @@ void HandleBranchAndRejoin(IApplicationBuilder app) app.Use(async (context, next) => { var branchVer = context.Request.Query["branch"]; - logger.LogInformation("Branch used = {branchVer}", branchVer); + logger.LogInformation("Branch used = {branchVer}", branchVer.ToString()); // Do work that doesn't write to the Response. await next(); @@ -810,7 +810,7 @@ void HandleBranchAndRejoin(IApplicationBuilder app) app.Use(async (context, next) => { var branchVer = context.Request.Query["branch"]; - logger.LogInformation("Branch used = {branchVer}", branchVer); + logger.LogInformation("Branch used = {branchVer}", branchVer.ToString()); // Do work that doesn't write to the Response. await next(); @@ -1226,7 +1226,7 @@ public class Startup app.Use(async (context, next) => { var branchVer = context.Request.Query["branch"]; - logger.LogInformation("Branch used = {branchVer}", branchVer); + logger.LogInformation("Branch used = {branchVer}", branchVer.ToString()); // Do work that doesn't write to the Response. await next(); From 472d0ddcea620628d23fa19bedd650d55107c86f Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 4 Feb 2026 08:21:59 -0500 Subject: [PATCH 15/16] Updates --- aspnetcore/fundamentals/middleware/index.md | 699 ++++++++- .../middleware/index/includes/index3-7.md | 1293 ----------------- 2 files changed, 690 insertions(+), 1302 deletions(-) delete mode 100644 aspnetcore/fundamentals/middleware/index/includes/index3-7.md diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index 250d64d8183f..7658f31e2d7c 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -6,15 +6,13 @@ description: Learn about ASP.NET Core middleware and the request pipeline. monikerRange: '>= aspnetcore-3.0' ms.author: tdykstra ms.custom: mvc -ms.date: 01/20/2026 +ms.date: 02/04/2026 uid: fundamentals/middleware/index --- # ASP.NET Core Middleware [!INCLUDE[](~/includes/not-latest-version.md)] -:::moniker range=">= aspnetcore-8.0" - Middleware is software that's assembled into an app pipeline to handle requests and responses. Each middleware: * Chooses whether to pass the request to the next middleware in the pipeline. @@ -28,7 +26,7 @@ For more information on the difference between request pipelines in ASP.NET Core ## Role of middleware by app type -Blazor Web Apps, Razor Pages, and MVC process browser requests on the server with middleware. The guidance in this article applies to these types of apps. +Server-side Blazor, Razor Pages, and MVC process browser requests on the server with middleware. The guidance in this article applies to these types of apps. Standalone Blazor WebAssembly apps run entirely on the client and don't process requests with a middleware pipeline. The guidance in this article doesn't apply to standalone Blazor WebAssembly apps. @@ -36,6 +34,8 @@ Standalone Blazor WebAssembly apps run entirely on the client and don't process For more information on ASP.NET Core's compiler platform analyzers that inspect app code for quality, see . +:::moniker range=">= aspnetcore-6.0" + ## Create a middleware pipeline with `WebApplication` The ASP.NET Core request pipeline consists of a sequence of request delegates, called one after the other. The following diagram demonstrates the concept. The thread of execution follows the black arrows. @@ -323,8 +323,224 @@ void HandleBranchAndRejoin(IApplicationBuilder app) In the preceding example, a response of ":::no-loc text="Hello from the non-Map delegate.":::" is written for all requests. If the request includes a query string variable named "`branch`," its value is logged before the main pipeline is rejoined. +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +## Create a middleware pipeline with `IApplicationBuilder` + +The ASP.NET Core request pipeline consists of a sequence of request delegates, called one after the other. The following diagram demonstrates the concept. The thread of execution follows the black arrows. + +![Request processing pattern showing a request arriving, processing through three middlewares, and the response leaving the app. Each middleware runs its logic and hands off the request to the next middleware at the next() statement. After the third middleware processes the request, the request passes back through the prior two middlewares in reverse order for additional processing after their next() statements before leaving the app as a response to the client.](~/fundamentals/middleware/index/_static/request-delegate-pipeline.png) + +Each delegate can perform operations before and after the next delegate. Exception-handling delegates should be called early in the pipeline, so they can catch exceptions that occur in later stages of the pipeline. + +The simplest possible ASP.NET Core app sets up a single request delegate that handles all requests. This case doesn't include an actual request pipeline. Instead, a single anonymous function is called in response to every HTTP request. + +```csharp +public class Startup +{ + public void Configure(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Hello, World!"); + }); + } +} +``` + +Chain multiple request delegates together with . The `next` parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by *not* calling the *next* parameter. You can typically perform actions both before and after the next delegate, as the following example demonstrates: + +```csharp +app.Use(async (context, next) => +{ + // Do work that doesn't write to the Response. + await next.Invoke(); + // Do logging or other work that doesn't write to the Response. +}); +``` + +When a delegate doesn't pass a request to the next delegate, it's called *short-circuiting the request pipeline*. Short-circuiting is often desirable because it avoids unnecessary work. For example, [Static File Middleware](xref:fundamentals/static-files) can act as a *terminal middleware* by processing a request for a static file and short-circuiting the rest of the pipeline. Middleware added to the pipeline before the middleware that terminates further processing still processes code after their `next.Invoke` statements. However, see the following warning about attempting to write to a response that has already been sent. + +> [!WARNING] +> Don't call `next.Invoke` after the response has been sent to the client. Changes to after the response has started throw an exception. For example, [setting headers and a status code throw an exception](xref:fundamentals/best-practices#do-not-modify-the-status-code-or-headers-after-the-response-body-has-started). Writing to the response body after calling `next`: +> +> * May cause a protocol violation. For example, writing more than the stated `Content-Length`. +> * May corrupt the body format. For example, writing an HTML footer to a CSS file. +> +> is a useful hint to indicate if headers have been sent or the body has been written to. + + delegates don't receive a `next` parameter. The first `Run` delegate is always terminal and terminates the pipeline. `Run` is a convention. Some middleware components may expose `Run[Middleware]` methods that run at the end of the pipeline: + +```csharp +app.Run(async context => +{ + await context.Response.WriteAsync("Hello from 2nd delegate."); +}); +``` + +In the preceding example, the `Run` delegate writes `"Hello from 2nd delegate."` to the response and then terminates the pipeline. If another `Use` or `Run` delegate is added after the `Run` delegate, it's not called. + +## Branch the middleware pipeline + + extensions are used as a convention for branching the pipeline. `Map` branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed. + +```csharp +public class Startup +{ + private static void HandleMapTest1(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 1"); + }); + } + + private static void HandleMapTest2(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Map Test 2"); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.Map("/map1", HandleMapTest1); + + app.Map("/map2", HandleMapTest2); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from non-Map delegate."); + }); + } +} +``` + +The following table shows the requests and responses from `http://localhost:1234` using the previous code. + +| Request | Response | +| ------------------- | ---------------------------- | +| localhost:1234 | Hello from non-Map delegate. | +| localhost:1234/map1 | Map Test 1 | +| localhost:1234/map2 | Map Test 2 | +| localhost:1234/map3 | Hello from non-Map delegate. | + +When `Map` is used, the matched path segments are removed from `HttpRequest.Path` and appended to `HttpRequest.PathBase` for each request. + +`Map` supports nesting, for example: + +```csharp +app.Map("/level1", level1App => { + level1App.Map("/level2a", level2AApp => { + // "/level1/level2a" processing + }); + level1App.Map("/level2b", level2BApp => { + // "/level1/level2b" processing + }); +}); +``` + +`Map` can also match multiple segments at once: + +```csharp +public class Startup +{ + private static void HandleMultiSeg(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Map multiple segments."); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.Map("/map1/seg1", HandleMultiSeg); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from non-Map delegate."); + }); + } +} +``` + + branches the request pipeline based on the result of the given predicate. Any predicate of type `Func` can be used to map requests to a new branch of the pipeline. In the following example, a predicate is used to detect the presence of a query string variable `branch`: + +```csharp +public class Startup +{ + private static void HandleBranch(IApplicationBuilder app) + { + app.Run(async context => + { + var branchVer = context.Request.Query["branch"]; + await context.Response.WriteAsync($"Branch used = {branchVer}"); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.MapWhen(context => context.Request.Query.ContainsKey("branch"), + HandleBranch); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from non-Map delegate."); + }); + } +} +``` + +The following table shows the requests and responses from `http://localhost:1234` using the previous code: + +| Request | Response | +| ----------------------------- | ---------------------------- | +| localhost:1234 | Hello from non-Map delegate. | +| localhost:1234/?branch=main | Branch used = main | + + also branches the request pipeline based on the result of the given predicate. Unlike with `MapWhen`, this branch is rejoined to the main pipeline if it doesn't short-circuit or contain a terminal middleware: + +```csharp +public class Startup +{ + private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger logger) + { + app.Use(async (context, next) => + { + var branchVer = context.Request.Query["branch"]; + logger.LogInformation("Branch used = {branchVer}", branchVer.ToString()); + + // Do work that doesn't write to the Response. + await next(); + // Do other work that doesn't write to the Response. + }); + } + + public void Configure(IApplicationBuilder app, ILogger logger) + { + app.UseWhen(context => context.Request.Query.ContainsKey("branch"), + appBuilder => HandleBranchAndRejoin(appBuilder, logger)); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from main pipeline."); + }); + } +} +``` + +In the preceding example, a response of "Hello from main pipeline." is written for all requests. If the request includes a query string variable `branch`, its value is logged before the main pipeline is rejoined. + +:::moniker-end + ## Middleware order +:::moniker range=">= aspnetcore-8.0" + The order that middleware appears in the app's `Program` file defines the order in which middleware are invoked on a request with the reverse order for the response. You have full control over the order of middleware and the ability to add custom middleware for request processing scenarios, keeping in mind that the order of middleware can be critical for security, performance, and functionality. @@ -427,6 +643,475 @@ Static assets are typically served early in the pipeline so that the app can sho Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization occurs after the framework selects a Razor component in a Blazor Web App, a page in a Razor Pages app, or a controller and action in an MVC app. +:::moniker-end + +:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" + +The following diagram shows the complete request processing pipeline for ASP.NET Core MVC and Razor Pages apps. You can see how, in a typical app, existing middlewares are ordered and where custom middlewares are added. You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios. + +![ASP.NET Core middleware pipeline](~/fundamentals/middleware/index/_static/middleware-pipeline.svg) + +The **Endpoint** middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. + +The **Routing** middleware in the preceding diagram is shown following **Static Files**. This is the order that the project templates implement by explicitly calling [app.UseRouting](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A). If you don't call `app.UseRouting`, the **Routing** middleware runs at the beginning of the pipeline by default. For more information, see [Routing](xref:fundamentals/routing). + +The order that middleware components are added in the `Program.cs` file defines the order in which the middleware components are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. + +The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: + +```csharp +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using WebMiddleware.Data; + +var builder = WebApplication.CreateBuilder(args); + +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") + ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); +builder.Services.AddControllersWithViews(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +// app.UseCookiePolicy(); + +app.UseRouting(); +// app.UseRateLimiter(); +// app.UseRequestLocalization(); +// app.UseCors(); + +app.UseAuthentication(); +app.UseAuthorization(); +// app.UseSession(); +// app.UseResponseCompression(); +// app.UseResponseCaching(); + +app.MapRazorPages(); +app.MapDefaultControllerRoute(); + +app.Run(); +``` + +In the preceding code: + +* Middleware that is not added when creating a new web app with [individual users accounts](xref:security/authentication/identity) is commented out. +* Not every middleware appears in this exact order, but many do. For example: + * `UseCors`, `UseAuthentication`, and `UseAuthorization` must appear in the order shown. + * `UseCors` currently must appear before `UseResponseCaching`. This requirement is explained in [GitHub issue dotnet/aspnetcore #23218](https://github.com/dotnet/aspnetcore/issues/23218). + * `UseRequestLocalization` must appear before any middleware that might check the request culture, for example, `app.UseStaticFiles()`. + * must be called after `UseRouting` when rate limiting endpoint specific APIs are used. For example, if the [`[EnableRateLimiting]`](xref:Microsoft.AspNetCore.RateLimiting.EnableRateLimitingAttribute) attribute is used, `UseRateLimiter` must be called after `UseRouting`. When calling only global limiters, `UseRateLimiter` can be called before `UseRouting`. + +In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there are multiple valid orderings. For example: + +```csharp +app.UseResponseCaching(); +app.UseResponseCompression(); +``` + +With the preceding code, CPU usage could be reduced by caching the compressed response, but you might end up caching multiple representations of a resource using different compression algorithms such as Gzip or Brotli. + +The following ordering combines static files to allow caching compressed static files: + +```csharp +app.UseResponseCaching(); +app.UseResponseCompression(); +app.UseStaticFiles(); +``` + +The following `Program.cs` code adds middleware components for common app scenarios: + +1. Exception/error handling + * When the app runs in the `Development` environment: + * Developer Exception Page Middleware () reports app runtime errors. + * Database Error Page Middleware () reports database runtime errors. + * When the app runs in the `Production` environment: + * Exception Handler Middleware () catches exceptions thrown in the following middlewares. + * HTTP Strict Transport Security Protocol (HSTS) Middleware () adds the `Strict-Transport-Security` header. +1. HTTPS Redirection Middleware () redirects HTTP requests to HTTPS. +1. Static File Middleware () returns static files and short-circuits further request processing. +1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR) regulations. +1. Routing Middleware () to route requests. +1. Authentication Middleware () attempts to authenticate the user before they're allowed access to secure resources. +1. Authorization Middleware () authorizes a user to access secure resources. +1. Session Middleware () establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before MVC Middleware. +1. Endpoint Routing Middleware ( with ) to add Razor Pages endpoints to the request pipeline. + +```csharp +if (env.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); + app.UseDatabaseErrorPage(); +} +else +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} +app.UseHttpsRedirection(); +app.UseStaticFiles(); +app.UseCookiePolicy(); +app.UseRouting(); +app.UseAuthentication(); +app.UseAuthorization(); +app.UseSession(); +app.MapRazorPages(); +``` + +In the preceding example code, each middleware extension method is exposed on through the namespace. + + is the first middleware component added to the pipeline. Therefore, the Exception Handler Middleware catches any exceptions that occur in later calls. + +Static File Middleware is called early in the pipeline so that it can handle requests and short-circuit without going through the remaining components. The Static File Middleware provides **no** authorization checks. Any files served by Static File Middleware, including those under *wwwroot*, are publicly available. For an approach to secure static files, see . + +If the request isn't handled by the Static File Middleware, it's passed on to the Authentication Middleware (), which performs authentication. Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization (and rejection) occurs only after MVC selects a specific Razor Page or MVC controller and action. + +The following example demonstrates a middleware order where requests for static files are handled by Static File Middleware before Response Compression Middleware. Static files aren't compressed with this middleware order. The Razor Pages responses can be compressed. + +```csharp +// Static files aren't compressed by Static File Middleware. +app.UseStaticFiles(); + +app.UseRouting(); + +app.UseResponseCompression(); + +app.MapRazorPages(); +``` + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" + +The following diagram shows the complete request processing pipeline for ASP.NET Core MVC and Razor Pages apps. You can see how, in a typical app, existing middlewares are ordered and where custom middlewares are added. You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios. + +![ASP.NET Core middleware pipeline](~/fundamentals/middleware/index/_static/middleware-pipeline.svg) + +The **Endpoint** middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. + +The **Routing** middleware in the preceding diagram is shown following **Static Files**. This is the order that the project templates implement by explicitly calling [app.UseRouting](xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A). If you don't call `app.UseRouting`, the **Routing** middleware runs at the beginning of the pipeline by default. For more information, see [Routing](xref:fundamentals/routing). + +The order that middleware components are added in the `Program.cs` file defines the order in which the middleware components are invoked on requests and the reverse order for the response. The order is **critical** for security, performance, and functionality. + +The following highlighted code in `Program.cs` adds security-related middleware components in the typical recommended order: + +```csharp +using IndividualAccountsExample.Data; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +// app.UseCookiePolicy(); + +app.UseRouting(); +// app.UseRequestLocalization(); +// app.UseCors(); + +app.UseAuthentication(); +app.UseAuthorization(); +// app.UseSession(); +// app.UseResponseCompression(); +// app.UseResponseCaching(); + +app.MapRazorPages(); +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + +app.Run(); +``` + +In the preceding code: + +* Middleware that is not added when creating a new web app with [individual users accounts](xref:security/authentication/identity) is commented out. +* Not every middleware appears in this exact order, but many do. For example: + * `UseCors`, `UseAuthentication`, and `UseAuthorization` must appear in the order shown. + * `UseCors` currently must appear before `UseResponseCaching`. This requirement is explained in [GitHub issue dotnet/aspnetcore #23218](https://github.com/dotnet/aspnetcore/issues/23218). + * `UseRequestLocalization` must appear before any middleware that might check the request culture (for example, `app.UseMvcWithDefaultRoute()`). + +In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there are multiple valid orderings. For example: + +```csharp +app.UseResponseCaching(); +app.UseResponseCompression(); +``` + +With the preceding code, CPU usage could be reduced by caching the compressed response, but you might end up caching multiple representations of a resource using different compression algorithms such as Gzip or Brotli. + +The following ordering combines static files to allow caching compressed static files: + +```csharp +app.UseResponseCaching(); +app.UseResponseCompression(); +app.UseStaticFiles(); +``` + +The following `Program.cs` code adds middleware components for common app scenarios: + +1. Exception/error handling + * When the app runs in the `Development` environment: + * Developer Exception Page Middleware () reports app runtime errors. + * Database Error Page Middleware () reports database runtime errors. + * When the app runs in the `Production` environment: + * Exception Handler Middleware () catches exceptions thrown in the following middlewares. + * HTTP Strict Transport Security Protocol (HSTS) Middleware () adds the `Strict-Transport-Security` header. +1. HTTPS Redirection Middleware () redirects HTTP requests to HTTPS. +1. Static File Middleware () returns static files and short-circuits further request processing. +1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR) regulations. +1. Routing Middleware () to route requests. +1. Authentication Middleware () attempts to authenticate the user before they're allowed access to secure resources. +1. Authorization Middleware () authorizes a user to access secure resources. +1. Session Middleware () establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before MVC Middleware. +1. Endpoint Routing Middleware ( with ) to add Razor Pages endpoints to the request pipeline. + +```csharp +if (env.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); + app.UseDatabaseErrorPage(); +} +else +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} +app.UseHttpsRedirection(); +app.UseStaticFiles(); +app.UseCookiePolicy(); +app.UseRouting(); +app.UseAuthentication(); +app.UseAuthorization(); +app.UseSession(); +app.MapRazorPages(); +``` + +In the preceding example code, each middleware extension method is exposed on through the namespace. + + is the first middleware component added to the pipeline. Therefore, the Exception Handler Middleware catches any exceptions that occur in later calls. + +Static File Middleware is called early in the pipeline so that it can handle requests and short-circuit without going through the remaining components. The Static File Middleware provides **no** authorization checks. Any files served by Static File Middleware, including those under *wwwroot*, are publicly available. For an approach to secure static files, see . + +If the request isn't handled by the Static File Middleware, it's passed on to the Authentication Middleware (), which performs authentication. Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization (and rejection) occurs only after MVC selects a specific Razor Page or MVC controller and action. + +The following example demonstrates a middleware order where requests for static files are handled by Static File Middleware before Response Compression Middleware. Static files aren't compressed with this middleware order. The Razor Pages responses can be compressed. + +```csharp +// Static files aren't compressed by Static File Middleware. +app.UseStaticFiles(); + +app.UseRouting(); + +app.UseResponseCompression(); + +app.MapRazorPages(); +``` + +:::moniker-end + +:::moniker range="< aspnetcore-6.0" + +The following diagram shows the complete request processing pipeline for ASP.NET Core MVC and Razor Pages apps. You can see how, in a typical app, existing middlewares are ordered and where custom middlewares are added. You have full control over how to reorder existing middlewares or inject new custom middlewares as necessary for your scenarios. + +![ASP.NET Core middleware pipeline](~/fundamentals/middleware/index/_static/middleware-pipeline.svg) + +The **Endpoint** middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages. + +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 order is **critical** for security, performance, and functionality. + +The following `Startup.Configure` method adds security-related middleware components in the typical recommended order: + +```csharp +public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +{ + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseDatabaseErrorPage(); + } + else + { + app.UseExceptionHandler("/Error"); + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseStaticFiles(); + // app.UseCookiePolicy(); + + app.UseRouting(); + // app.UseRequestLocalization(); + // app.UseCors(); + + app.UseAuthentication(); + app.UseAuthorization(); + // app.UseSession(); + // app.UseResponseCompression(); + // app.UseResponseCaching(); + + app.UseEndpoints(endpoints => + { + endpoints.MapRazorPages(); + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + }); +} +``` + +In the preceding code: + +* Middleware that is not added when creating a new web app with [individual users accounts](xref:security/authentication/identity) is commented out. +* Not every middleware appears in this exact order, but many do. For example: + * `UseCors`, `UseAuthentication`, and `UseAuthorization` must appear in the order shown. + * `UseCors` currently must appear before `UseResponseCaching` due to [this bug](https://github.com/dotnet/aspnetcore/issues/23218). + * `UseRequestLocalization` must appear before any middleware that might check the request culture (for example, `app.UseMvcWithDefaultRoute()`). + +In some scenarios, middleware has different ordering. For example, caching and compression ordering is scenario specific, and there's multiple valid orderings. For example: + +```csharp +app.UseResponseCaching(); +app.UseResponseCompression(); +``` + +With the preceding code, CPU could be saved by caching the compressed response, but you might end up caching multiple representations of a resource using different compression algorithms such as Gzip or Brotli. + +The following ordering combines static files to allow caching compressed static files: + +```csharp +app.UseResponseCaching(); +app.UseResponseCompression(); +app.UseStaticFiles(); +``` + +The following `Startup.Configure` method adds middleware components for common app scenarios: + +1. Exception/error handling + * When the app runs in the `Development` environment: + * Developer Exception Page Middleware () reports app runtime errors. + * Database Error Page Middleware reports database runtime errors. + * When the app runs in the `Production` environment: + * Exception Handler Middleware () catches exceptions thrown in the following middlewares. + * HTTP Strict Transport Security Protocol (HSTS) Middleware () adds the `Strict-Transport-Security` header. +1. HTTPS Redirection Middleware () redirects HTTP requests to HTTPS. +1. Static File Middleware () returns static files and short-circuits further request processing. +1. Cookie Policy Middleware () conforms the app to the EU General Data Protection Regulation (GDPR) regulations. +1. Routing Middleware () to route requests. +1. Authentication Middleware () attempts to authenticate the user before they're allowed access to secure resources. +1. Authorization Middleware () authorizes a user to access secure resources. +1. Session Middleware () establishes and maintains session state. If the app uses session state, call Session Middleware after Cookie Policy Middleware and before MVC Middleware. +1. Endpoint Routing Middleware ( with ) to add Razor Pages endpoints to the request pipeline. + +```csharp +public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +{ + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseDatabaseErrorPage(); + } + else + { + app.UseExceptionHandler("/Error"); + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseStaticFiles(); + app.UseCookiePolicy(); + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + app.UseSession(); + + app.UseEndpoints(endpoints => + { + endpoints.MapRazorPages(); + }); +} +``` + +In the preceding example code, each middleware extension method is exposed on through the namespace. + + is the first middleware component added to the pipeline. Therefore, the Exception Handler Middleware catches any exceptions that occur in later calls. + +Static File Middleware is called early in the pipeline so that it can handle requests and short-circuit without going through the remaining components. The Static File Middleware provides **no** authorization checks. Any files served by Static File Middleware, including those under *wwwroot*, are publicly available. For an approach to secure static files, see . + +If the request isn't handled by the Static File Middleware, it's passed on to the Authentication Middleware (), which performs authentication. Authentication doesn't short-circuit unauthenticated requests. Although Authentication Middleware authenticates requests, authorization (and rejection) occurs only after MVC selects a specific Razor Page or MVC controller and action. + +The following example demonstrates a middleware order where requests for static files are handled by Static File Middleware before Response Compression Middleware. Static files aren't compressed with this middleware order. The Razor Pages responses can be compressed. + +```csharp +public void Configure(IApplicationBuilder app) +{ + // Static files aren't compressed by Static File Middleware. + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseResponseCompression(); + + app.UseEndpoints(endpoints => + { + endpoints.MapRazorPages(); + }); +} +``` + +For Single Page Applications (SPAs), the SPA middleware usually comes last in the middleware pipeline. The SPA middleware comes last: + +* To allow all other middlewares to respond to matching requests first. +* To allow SPAs with client-side routing to run for all routes that are unrecognized by the server app. + +For more details on SPAs, see the guides for the [React](xref:spa/react) and [Angular](xref:spa/angular) project templates. + +:::moniker-end + +For information about Single Page Applications, see the guides for the [React](xref:spa/react) and [Angular](xref:spa/angular) project templates. + ## `UseCors` and `UseStaticFiles` order For more information on ordering and , see . @@ -437,7 +1122,7 @@ Run Forwarded Headers Middleware before other middleware to ensure that the midd ## Built-in middleware -ASP.NET Core ships with the following middleware. The *UI stack* column indicates the typical UI stack where the middleware is used [All, Blazor Web App (BWA), Razor Pages and MVC (RP/MVC)]. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section. +The latest release of ASP.NET Core ships with the following middleware. The *UI stack* column indicates the typical UI stack where the middleware is used [All, Blazor Web App (BWA), Razor Pages and MVC (RP/MVC)]. The *Order* column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a *terminal middleware*. For more information on short-circuiting, see the [Create a middleware pipeline with `WebApplication`](#create-a-middleware-pipeline-with-webapplication) section.