diff --git a/aspnetcore/fundamentals/minimal-apis/includes/middleware8.md b/aspnetcore/fundamentals/minimal-apis/includes/middleware8.md index e4fac5ce2335..56c7869a1fc2 100644 --- a/aspnetcore/fundamentals/minimal-apis/includes/middleware8.md +++ b/aspnetcore/fundamentals/minimal-apis/includes/middleware8.md @@ -1,11 +1,17 @@ :::moniker range=">= aspnetcore-8.0" -[`WebApplication`](xref:fundamentals/minimal-apis/webapplication) automatically adds the following middleware in [Minimal API applications](xref:fundamentals/apis) depending on certain conditions: -* [`UseDeveloperExceptionPage`](/dotnet/api/microsoft.aspnetcore.diagnostics.developerexceptionpagemiddleware) is added first when the [`HostingEnvironment`](xref:fundamentals/environments) is `"Development"`. -* [`UseRouting`](/dotnet/api/microsoft.aspnetcore.builder.endpointroutingapplicationbuilderextensions.userouting) is added second if user code didn't already call `UseRouting` and if there are endpoints configured, for example `app.MapGet`. -* [`UseEndpoints`](/dotnet/api/microsoft.aspnetcore.builder.endpointroutingapplicationbuilderextensions.useendpoints) is added at the end of the middleware pipeline if any endpoints are configured. -* [`UseAuthentication`](/dotnet/api/microsoft.aspnetcore.builder.authappbuilderextensions.useauthentication) is added immediately after `UseRouting` if user code didn't already call `UseAuthentication` and if [`IAuthenticationSchemeProvider`](/dotnet/api/microsoft.aspnetcore.authentication.iauthenticationschemeprovider) can be detected in the service provider. `IAuthenticationSchemeProvider` is added by default when using [`AddAuthentication`](/dotnet/api/microsoft.extensions.dependencyinjection.authenticationservicecollectionextensions.addauthentication), and services are detected using [`IServiceProviderIsService`](/dotnet/api/microsoft.extensions.dependencyinjection.iserviceproviderisservice). -* [`UseAuthorization`](/dotnet/api/microsoft.aspnetcore.builder.authorizationappbuilderextensions.useauthorization) is added next if user code didn't already call `UseAuthorization` and if [`IAuthorizationHandlerProvider`](/dotnet/api/microsoft.aspnetcore.authorization.iauthorizationhandlerprovider) can be detected in the service provider. `IAuthorizationHandlerProvider` is added by default when using [`AddAuthorization`](/dotnet/api/microsoft.extensions.dependencyinjection.authenticationservicecollectionextensions.addauthentication), and services are detected using `IServiceProviderIsService`. +[WebApplication](xref:fundamentals/minimal-apis/webapplication) automatically adds the following middleware in [Minimal API applications](xref:fundamentals/apis) depending on certain conditions: + +* [UseDeveloperExceptionPage](/dotnet/api/microsoft.aspnetcore.diagnostics.developerexceptionpagemiddleware) is added first when the [HostingEnvironment](xref:fundamentals/environments) is `"Development"`. + +* [UseRouting](/dotnet/api/microsoft.aspnetcore.builder.endpointroutingapplicationbuilderextensions.userouting) is added second, if the user code didn't already call `UseRouting` and endpoints are configured, for example `app.MapGet`. + +* [UseEndpoints](/dotnet/api/microsoft.aspnetcore.builder.endpointroutingapplicationbuilderextensions.useendpoints) is added at the end of the middleware pipeline if endpoints are configured. + +* [UseAuthentication](/dotnet/api/microsoft.aspnetcore.builder.authappbuilderextensions.useauthentication) is added immediately after `UseRouting`, if user code didn't already call `UseAuthentication` and if [IAuthenticationSchemeProvider](/dotnet/api/microsoft.aspnetcore.authentication.iauthenticationschemeprovider) can be detected in the service provider. `IAuthenticationSchemeProvider` is added by default when you use [AddAuthentication](/dotnet/api/microsoft.extensions.dependencyinjection.authenticationservicecollectionextensions.addauthentication), and services are detected by using [IServiceProviderIsService](/dotnet/api/microsoft.extensions.dependencyinjection.iserviceproviderisservice). + +* [UseAuthorization](/dotnet/api/microsoft.aspnetcore.builder.authorizationappbuilderextensions.useauthorization) is added next, if user code didn't already call `UseAuthorization` and if [IAuthorizationHandlerProvider](/dotnet/api/microsoft.aspnetcore.authorization.iauthorizationhandlerprovider) can be detected in the service provider. `IAuthorizationHandlerProvider` is added by default when you use [AddAuthorization](/dotnet/api/microsoft.extensions.dependencyinjection.authenticationservicecollectionextensions.addauthentication), and services are detected by using `IServiceProviderIsService`. + * User configured middleware and endpoints are added between `UseRouting` and `UseEndpoints`. The following code is effectively what the automatic middleware being added to the app produces: @@ -28,10 +34,10 @@ if (isAuthorizationConfigured) app.UseAuthorization(); } -// user middleware/endpoints +// User middleware/endpoints app.CustomMiddleware(...); app.MapGet("/", () => "hello world"); -// end user middleware/endpoints +// End user middleware/endpoints app.UseEndpoints(e => {}); ``` @@ -44,7 +50,7 @@ app.UseAuthentication(); app.UseAuthorization(); ``` -If middleware should be run before route matching occurs, should be called and the middleware should be placed before the call to `UseRouting`. isn't required in this case as it is automatically added as described previously: +If middleware should run before route matching occurs, should be called and the middleware should be placed before the call to `UseRouting`. isn't required in this case because it's automatically added as described earlier: ```csharp app.Use((context, next) => @@ -54,13 +60,15 @@ app.Use((context, next) => app.UseRouting(); -// other middleware and endpoints +// Other middleware and endpoints ``` When adding a terminal middleware: * The middleware must be added after `UseEndpoints`. -* The app needs to call `UseRouting` and `UseEndpoints` so that the terminal middleware can be placed at the correct location. + +* The app needs to call `UseRouting` and `UseEndpoints` so the terminal middleware can be placed at the correct location. + ```csharp app.UseRouting(); @@ -77,6 +85,6 @@ app.Run(context => Terminal middleware is middleware that runs if no endpoint handles the request. -For information on antiforgery middleware in Minimal APIs, see +For information on antiforgery middleware in Minimal APIs, see . :::moniker-end diff --git a/aspnetcore/fundamentals/minimal-apis/includes/route-handlers.md b/aspnetcore/fundamentals/minimal-apis/includes/route-handlers.md index 559a06f0e67a..e77751788ecc 100644 --- a/aspnetcore/fundamentals/minimal-apis/includes/route-handlers.md +++ b/aspnetcore/fundamentals/minimal-apis/includes/route-handlers.md @@ -1,4 +1,6 @@ -Route handlers are methods that execute when the route matches. Route handlers can be a lambda expression, a local function, an instance method or a static method. Route handlers can be synchronous or asynchronous. +Route handlers are methods that execute when the route matches. Route handlers can be a lambda expression, a local function, an instance method, or a static method. Route handlers can be synchronous or asynchronous. + +The following sections provide examples of different route handlers. ### Lambda expression @@ -16,58 +18,61 @@ Route handlers are methods that execute when the route matches. Route handlers c [!code-csharp[](~/fundamentals/minimal-apis/7.0-samples/WebMinAPIs/Program.cs?name=snippet_sm)] -### Endpoint defined outside of `Program.cs` +### Endpoint defined outside of Program.cs -Minimal APIs don't have to be located in `Program.cs`. +Minimal APIs don't have to be located in the _Program.cs_ file. For example, you can set up the structure in the _Program.cs_ file, and define the endpoint in a separate file: -`Program.cs` +**Program.cs** [!code-csharp[](~/fundamentals/minimal-apis/8.0-samples/MinAPISeparateFile/Program.cs)] -`TodoEndpoints.cs` +**TodoEndpoints.cs** [!code-csharp[](~/fundamentals/minimal-apis/8.0-samples/MinAPISeparateFile/TodoEndpoints.cs)] -See also [Route groups](#route-groups) later in this article. +For more information, see the [Route groups](#route-groups) section later in this article. ### Named endpoints and link generation -Endpoints can be given names in order to generate URLs to the endpoint. Using a named endpoint avoids having to hard code paths in an app: +You can supply a name for your endpoints to generate URLs that target the endpoint. Using a named endpoint avoids having to hard code paths in an app: [!code-csharp[](~/fundamentals/minimal-apis/samples/WebMinAPIs/Program.cs?name=snippet_nr)] -The preceding code displays `The link to the hello route is /hello` from the `/` endpoint. +The preceding code displays the message _`The link to the hello route is /hello`_ from the `/` (forward slash) endpoint. -**NOTE**: Endpoint names are case sensitive. +#### Criteria for endpoint names -Endpoint names: +Endpoint names must satisfy the following criteria: -* Must be globally unique. -* Are used as the OpenAPI operation id when OpenAPI support is enabled. For more information, see [OpenAPI](xref:fundamentals/openapi/aspnetcore-openapi). +* Endpoint names are case sensitive. +* Endpoint names must be globally unique. +* Endpoint names are used as the OpenAPI operation identifier (ID) when OpenAPI support is enabled. For more information, see [Generate OpenAPI documents](xref:fundamentals/openapi/aspnetcore-openapi). -### Route Parameters +### Route parameters Route parameters can be captured as part of the route pattern definition: [!code-csharp[](~/fundamentals/minimal-apis/7.0-samples/WebMinAPIs/Program.cs?name=snippet_rp)] -The preceding code returns `The user id is 3 and book id is 7` from the URI `/users/3/books/7`. +The preceding code returns the message _The user id is 3 and book id is 7_ from the URI `/users/3/books/7`. -The route handler can declare the parameters to capture. When a request is made to a route with parameters declared to capture, the parameters are parsed and passed to the handler. This makes it easy to capture the values in a type safe way. In the preceding code, `userId` and `bookId` are both `int`. +The route handler can declare the parameters to capture. When a request is made to a route with parameters declared to capture, the parameters are parsed and passed to the handler. This approach makes it easy to capture the values in a type-safe way. In the preceding code, the `userId` and `bookId` parameters are both type `int`. -In the preceding code, if either route value cannot be converted to an `int`, an exception is thrown. The GET request `/users/hello/books/3` throws the following exception: +In the preceding code, if either route value can't be converted to an `int`, an exception is thrown. The GET request `/users/hello/books/3` throws the following exception: -**`BadHttpRequestException: Failed to bind parameter "int userId" from "hello".`** +```output +BadHttpRequestException: Failed to bind parameter "int userId" from "hello". +``` ### Wildcard and catch all routes -The following catch all route returns `Routing to hello` from the `/posts/hello' endpoint: +The following catch all route returns _Routing to hello_ from the `/posts/hello` endpoint: [!code-csharp[](~/fundamentals/minimal-apis/7.0-samples/WebMinAPIs/Program.cs?name=snippet_wild)] ### Route constraints -Route constraints constrain the matching behavior of a route. +Route constraints restrict the matching behavior of a route. ```csharp var builder = WebApplication.CreateBuilder(args); @@ -82,13 +87,13 @@ app.Run(); The following table demonstrates the preceding route templates and their behavior: -| Route Template | Example Matching URI | -|--|--| +| Route template | Example matching URI | +|---|---| | `/todos/{id:int}` | `/todos/1` | | `/todos/{text}` | `/todos/something` | | `/posts/{slug:regex(^[a-z0-9_-]+$)}` | `/posts/mypost` | -For more information, see [Route constraint reference](xref:fundamentals/routing) in . +For more information, see [Route constraint reference](xref:fundamentals/routing#route-constraints) in . ### Route groups diff --git a/aspnetcore/fundamentals/minimal-apis/middleware.md b/aspnetcore/fundamentals/minimal-apis/middleware.md index a9ba02681de9..54f0e138b9a2 100644 --- a/aspnetcore/fundamentals/minimal-apis/middleware.md +++ b/aspnetcore/fundamentals/minimal-apis/middleware.md @@ -1,20 +1,28 @@ --- title: Middleware with Minimal API applications author: BrennanConroy -description: Use middleware in Minimal API applications +description: Use middleware in Minimal API applications, including automatic middleware, user-configured middleware, and terminal middleware. ms.author: wpickett -ms.date: 02/16/2024 +ms.date: 04/28/2026 monikerRange: '>= aspnetcore-7.0' uid: fundamentals/minimal-apis/middleware + +# customer intent: As an ASP.NET developer, I want to use middleware in ASP.NET Core, so I can use the functionality to handle requests and responses in my Minimal API apps. --- # Middleware in Minimal API apps [!INCLUDE[](~/includes/not-latest-version.md)] +This article describes how to use middleware in Minimal API applications. Take advantage of automatic middleware in your Minimal API apps, or define user-configured middleware and terminal middleware. + +## Available middleware + [!INCLUDE [webapplication7](~/fundamentals/minimal-apis/includes/middleware7.md)] [!INCLUDE [webapplication8](~/fundamentals/minimal-apis/includes/middleware8.md)] -For more information about middleware see [ASP.NET Core Middleware](xref:fundamentals/middleware/index), and the [list of built-in middleware](xref:fundamentals/middleware/index#built-in-middleware) that can be added to applications. +## Related content -For more information about Minimal APIs see [APIs overview](xref:fundamentals/apis). +- [ASP.NET Core Middleware](xref:fundamentals/middleware/index) +- [Built-in middleware (list)](xref:fundamentals/middleware/index#built-in-middleware) +- [Minimal APIs overview](xref:fundamentals/apis) \ No newline at end of file diff --git a/aspnetcore/fundamentals/minimal-apis/min-api-filters.md b/aspnetcore/fundamentals/minimal-apis/min-api-filters.md index 84214f13eef4..93abd8dbf1b5 100644 --- a/aspnetcore/fundamentals/minimal-apis/min-api-filters.md +++ b/aspnetcore/fundamentals/minimal-apis/min-api-filters.md @@ -1,11 +1,13 @@ --- title: Filters in Minimal API apps author: wadepickett -description: Use filters in Minimal API apps +description: Use filters in Minimal API apps, including validation of an object with a filter, and registering a filter. ms.author: wpickett -ms.date: 8/11/2022 +ms.date: 04/28/2026 monikerRange: '>= aspnetcore-7.0' uid: fundamentals/minimal-apis/min-api-filters + +# customer intent: As an ASP.NET developer, I want to use filters in Minimal APIs, so I can validate and log request and response data for my apps. --- # Filters in Minimal API apps @@ -14,33 +16,37 @@ uid: fundamentals/minimal-apis/min-api-filters By [Fiyaz Bin Hasan](https://github.com/fiyazbinhasan), [Martin Costello](https://twitter.com/martin_costello), and [Rick Anderson](https://twitter.com/RickAndMSFT) -Minimal API filters allow developers to implement business logic that supports: +Minimal API filters allow developers to implement business logic that supports the following tasks: + +* Run code before and after the endpoint handler +* Inspect and modify parameters provided during an endpoint handler invocation +* Intercept the response behavior of an endpoint handler + +Filters are helpful in many scenarios: -* Running code before and after the endpoint handler. -* Inspecting and modifying parameters provided during an endpoint handler invocation. -* Intercepting the response behavior of an endpoint handler. +* Validate request parameters and body sent to an endpoint +* Log information about the request and response +* Validate a request targets a supported API version -Filters can be helpful in the following scenarios: +This article describes how to use filters in your Minimal API apps, such as for validating request data sent to your app and logging the response. -* Validating the request parameters and body that are sent to an endpoint. -* Logging information about the request and response. -* Validating that a request is targeting a supported API version. +## Work with filters -Filters can be registered by providing a [Delegate](/dotnet/csharp/programming-guide/delegates/) that takes a [`EndpointFilterInvocationContext`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/EndpointFilterInvocationContext.cs) and returns a [`EndpointFilterDelegate`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/EndpointFilterDelegate.cs). The `EndpointFilterInvocationContext` provides access to the `HttpContext` of the request and an `Arguments` list indicating the arguments passed to the handler in the order in which they appear in the declaration of the handler. +Filters are registered by providing a [Delegate](/dotnet/csharp/programming-guide/delegates/) that takes a [EndpointFilterInvocationContext](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/EndpointFilterInvocationContext.cs) and returns a [EndpointFilterDelegate](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/EndpointFilterDelegate.cs). The `EndpointFilterInvocationContext` provides access to the `HttpContext` of the request and an `Arguments` list. The list specifies the arguments passed to the handler in the order in which they appear in the declaration of the handler. [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/Filters/Program.cs?name=snippet1)] The preceding code: * Calls the `AddEndpointFilter` extension method to add a filter to the `/colorSelector/{color}` endpoint. -* Returns the color specified except for the value `"Red"`. +* Returns the color specified, except for the value `"Red"`. * Returns [Results.Problem](xref:Microsoft.AspNetCore.Http.Results.Problem%2A) when the `/colorSelector/Red` is requested. -* Uses `next` as the `EndpointFilterDelegate` and `invocationContext` as the `EndpointFilterInvocationContext` to invoke the next filter in the pipeline or the request delegate if the last filter has been invoked. +* Uses `next` as the `EndpointFilterDelegate` and `invocationContext` as the `EndpointFilterInvocationContext` to invoke the next filter in the pipeline, or the request delegate if the last filter is already invoked. -The filter is run before the endpoint handler. When multiple `AddEndpointFilter` invocations are made on a handler: +The filter runs before the endpoint handler. When multiple `AddEndpointFilter` invocations are made on a handler: -* Filter code called before the `EndpointFilterDelegate` (`next`) is called are executed in order of First In, First Out (FIFO) order. -* Filter code called after the `EndpointFilterDelegate` (`next`) is called are executed in order of First In, Last Out (FILO) order. +* The execution order of filter code called _before_ the call to `EndpointFilterDelegate` (`next`) is First In, First Out (FIFO). +* The execution order of filter code called _after_ the call to `EndpointFilterDelegate` (`next`) is First In, Last Out (FILO). [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/Filters/Program.cs?name=snippet_xyz)] @@ -60,7 +66,7 @@ The following code uses filters that implement the `IEndpointFilter` interface: [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/Filters/Program.cs?name=snippet_abc)] -In the preceding code, the filters and handlers logs show the order they are run: +In the preceding code, the logs for the filters and handlers show the run order: ```dotnetcli AEndpointFilter Before next @@ -72,7 +78,7 @@ BEndpointFilter After next AEndpointFilter After next ``` -Filters implementing the `IEndpointFilter` interface are shown in the following example: +Filters that implement the `IEndpointFilter` interface are shown in the following example: [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/Filters/EndpointFilters/AbcEndpointFilters.cs)] @@ -85,13 +91,13 @@ Consider a filter that validates a `Todo` object: In the preceding code: * The `EndpointFilterInvocationContext` object provides access to the parameters associated with a particular request issued to the endpoint via the `GetArguments` method. -* The filter is registered using a `delegate` that takes a `EndpointFilterInvocationContext` and returns a `EndpointFilterDelegate`. +* The filter is registered by using a `delegate` that takes a `EndpointFilterInvocationContext` and returns a `EndpointFilterDelegate`. -In addition to being passed as delegates, filters can be registered by implementing the `IEndpointFilter` interface. The following code shows the preceding filter encapsulated in a class which implements `IEndpointFilter`: +In addition to being passed as delegates, filters can be registered by implementing the `IEndpointFilter` interface. The following code shows the preceding filter encapsulated in a class that implements `IEndpointFilter`: [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/todo/EndpointFilters/ToDoIsValidFilter.cs?name=snippet)] -Filters that implement the `IEndpointFilter` interface can resolve dependencies from [Dependency Injection(DI)](xref:fundamentals/dependency-injection), as shown in the previous code. Although filters can resolve dependencies from DI, filters themselves can ***not*** be resolved from DI. +Filters that implement the `IEndpointFilter` interface can resolve dependencies from [Dependency Injection (DI)](xref:fundamentals/dependency-injection), as shown in the previous code. Although filters can resolve dependencies from DI, filters themselves **can't** be resolved from DI. The `ToDoIsValidFilter` is applied to the following endpoints: @@ -101,27 +107,27 @@ The following filter validates the `Todo` object and modifies the `Name` propert [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/todo/EndpointFilters/ToDoIsValidFilter.cs?name=snippet2&highlight=7)] -## Register a filter using an endpoint filter factory +## Register a filter by using an endpoint filter factory -In some scenarios, it might be necessary to cache some of the information provided in the [`MethodInfo`](/dotnet/api/system.reflection.methodinfo) in a filter. For example, let's assume that we wanted to verify that the handler an endpoint filter is attached to has a first parameter that evaluates to a `Todo` type. +In some scenarios, it might be necessary to cache some of the information provided in the [MethodInfo](/dotnet/api/system.reflection.methodinfo) in a filter. Suppose you want to verify that the handler attached to an endpoint filter has a first parameter that evaluates to a `Todo` type. [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/todo/Program.cs?name=snippet_filterfactory1)] In the preceding code: -* The `EndpointFilterFactoryContext` object provides access to the [`MethodInfo`](/dotnet/api/system.reflection.methodinfo) associated with the endpoint's handler. +* The `EndpointFilterFactoryContext` object provides access to the [MethodInfo](/dotnet/api/system.reflection.methodinfo) associated with the endpoint's handler. * The signature of the handler is examined by inspecting `MethodInfo` for the expected type signature. If the expected signature is found, the validation filter is registered onto the endpoint. This factory pattern is useful to register a filter that depends on the signature of the target endpoint handler. -* If a matching signature isn't found, then a pass-through filter is registered. +* If a matching signature isn't found, a pass-through filter is registered. ## Register a filter on controller actions -In some scenarios, it might be necessary to apply the same filter logic for both route-handler based endpoints and controller actions. For this scenario, it is possible to invoke `AddEndpointFilter` on `ControllerActionEndpointConventionBuilder` to support executing the same filter logic on actions and endpoints. +In some scenarios, it might be necessary to apply the same filter logic for both route-handler based endpoints and controller actions. For this scenario, you can invoke `AddEndpointFilter` on `ControllerActionEndpointConventionBuilder` to support executing the same filter logic on actions and endpoints. [!code-csharp[](~/fundamentals/minimal-apis/min-api-filters/7samples/Filters/Program.cs?name=snippet_action_endpoint_filters)] -## Additional Resources +## Related content -* [View or download sample code](https://github.com/aspnet/Docs/tree/main/aspnetcore/fundamentals/minimal-apis/min-api-filters/7samples) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) -* [ValidationFilterRouteHandlerBuilderExtensions](https://github.com/DamianEdwards/MinimalApis.Extensions/blob/main/src/MinimalApis.Extensions/Filters/ValidationFilterRouteHandlerBuilderExtensions.cs) Validation extension methods. -* -* +* [View or download sample code](https://github.com/aspnet/Docs/tree/main/aspnetcore/fundamentals/minimal-apis/min-api-filters/7samples) ([How to download](xref:fundamentals/index#how-to-download-a-sample)) +* [ValidationFilterRouteHandlerBuilderExtensions (Validation extension methods)](https://github.com/DamianEdwards/MinimalApis.Extensions/blob/main/src/MinimalApis.Extensions/Filters/ValidationFilterRouteHandlerBuilderExtensions.cs) +* [Tutorial: Create a Minimal API with ASP.NET Core](xref:tutorials/min-web-api) +* [Authentication and authorization in Minimal APIs](xref:fundamentals/minimal-apis/security) \ No newline at end of file diff --git a/aspnetcore/fundamentals/minimal-apis/route-handlers.md b/aspnetcore/fundamentals/minimal-apis/route-handlers.md index bf33e64e501d..4aa6d779b20d 100644 --- a/aspnetcore/fundamentals/minimal-apis/route-handlers.md +++ b/aspnetcore/fundamentals/minimal-apis/route-handlers.md @@ -1,31 +1,41 @@ --- title: Route handlers in Minimal API apps author: wadepickett -description: Learn how to handle requests in Minimal API apps. +description: Learn how to handle route requests in Minimal API apps, define preferred methods, bind route parameters, and process the request response. ms.author: wpickett monikerRange: '>= aspnetcore-7.0' -ms.date: 10/31/2022 +ms.date: 04/28/2026 uid: fundamentals/minimal-apis/route-handlers + +# customer intent: As an ASP.NET developer, I want to use route handlers in Minimal APIs, so I can define my preferred methods to execute when a route matches. --- -# Route Handlers in Minimal API apps +# Route handlers in Minimal API apps [!INCLUDE[](~/includes/not-latest-version.md)] -A configured `WebApplication` supports `Map{Verb}` and where `{Verb}` is a Pascal-cased HTTP method like `Get`, `Post`, `Put` or `Delete`: +A configured `WebApplication` supports `Map{Verb}` and the , where `{Verb}` is a Pascal-cased HTTP method like `Get`, `Post`, `Put`, or `Delete`: [!code-csharp[](7.0-samples/WebMinAPIs/Program.cs?name=snippet_r1)] -The arguments passed to these methods are called "route handlers". +The arguments passed to these methods are called _route handlers_. + +This article describes how to use route handlers, including examples, parameters, route groups, and route constraints. -## Route handlers +## Work with route handlers [!INCLUDE [route handling](includes/route-handlers.md)] -## Parameter binding +## Bind parameters in a route handler describes the rules in detail for how route handler parameters are populated. -## Responses +## Handle the response from the route handler describes in detail how values returned from route handlers are converted into responses. + +## Related content + +- [Routing in ASP.NET Core](xref:fundamentals/routing) +- [Parameter Binding in Minimal API apps](xref:fundamentals/minimal-apis/parameter-binding) +- [Filters in Minimal API apps](xref:fundamentals/minimal-apis/min-api-filters) \ No newline at end of file diff --git a/aspnetcore/fundamentals/minimal-apis/security.md b/aspnetcore/fundamentals/minimal-apis/security.md index 28c2652d1219..0da1322f2a64 100644 --- a/aspnetcore/fundamentals/minimal-apis/security.md +++ b/aspnetcore/fundamentals/minimal-apis/security.md @@ -1,60 +1,72 @@ --- title: Authentication and authorization in Minimal APIs author: wadepickett -description: Learn how to configure authentication and authorization in Minimal API apps +description: Learn how to configure authentication and authorization in Minimal API apps, explore concepts, define policies, and run development tests. ms.author: wpickett content_well_notification: AI-contribution monikerRange: '>= aspnetcore-7.0' -ms.date: 9/17/2023 +ms.date: 04/28/2026 uid: fundamentals/minimal-apis/security ai-usage: ai-assisted + +# customer intent: As an ASP.NET developer, I want to use authentication and authorization in Minimal API apps, so I can manage user access to my apps. --- # Authentication and authorization in Minimal APIs [!INCLUDE[](~/includes/not-latest-version.md)] -Minimal APIs support all the authentication and authorization options available in ASP.NET Core and provide some additional functionality to improve the experience working with authentication. +Minimal APIs support all authentication and authorization options available in ASP.NET Core, and provide extra functionality to improve the experience for managing authentication. + +This article describes the support for authentication and authorization in Minimal API applications, and how to configure and test the functionality. + +## Review authentication and authorization concepts + +Authentication is the process of determining a user's identity while authorization is the process of determining whether a user has access to a resource. Both authentication and authorization scenarios share similar implementation semantics in ASP.NET Core. -## Key concepts in authentication and authorization +- The authentication service, [IAuthenticationService](/dotnet/api/microsoft.aspnetcore.authentication.iauthenticationservice), handles all authentication and is used by authentication [middleware](./middleware.md). +- The authorization service, [IAuthorizationService](/dotnet/api/microsoft.aspnetcore.authorization.iauthorizationservice), manages all authorization and is used by the authorization middleware. -Authentication is the process of determining a user's identity. Authorization is the process of determining whether a user has access to a resource. Both authentication and authorization scenarios share similar implementation semantics in ASP.NET Core. Authentication is handled by the authentication service, [IAuthenticationService](/dotnet/api/microsoft.aspnetcore.authentication.iauthenticationservice), which is used by authentication [middleware](/aspnet/core/fundamentals/middleware). Authorization is handled by the authorization service, [IAuthorizationService](/dotnet/api/microsoft.aspnetcore.authorization.iauthorizationservice), which is used by the authorization middleware. +### Authentication service The authentication service uses registered authentication handlers to complete authentication-related actions. For example, an authentication-related action is authenticating a user or signing out a user. Authentication schemes are names that are used to uniquely identify an authentication handler and its configuration options. Authentication handlers are responsible for implementing the strategies for authentication and generating a user's claims given a particular authentication strategy, such as OAuth or OIDC. The configuration options are unique to the strategy as well and provide the handler with configuration that affects authentication behavior, such as redirect URIs. -There are two strategies for determining user access to resources in the authorization layer: +### Authorization service -* Role-based strategies determine a user's access based on the role they are assigned, such as `Administrator` or `User`. For more information on role-based authorization, see [role-based authorization documentation](/aspnet/core/security/authorization/roles). -* Claim-based strategies determine a user's access based on claims that are issued by a central authority. For more information on claim-based authorization, see [claim-based authorization documentation](/aspnet/core/security/authorization/claims). +In the authorization layer, there are two strategies for determining user access to resources: -In ASP.NET Core, both strategies are captured into an authorization requirement. The authorization service leverages authorization handlers to determine whether or not a particular user meets the authorization requirements applied onto a resource. +- **Role-based strategies** determine a user's access based on their assigned role, such as `Administrator` or `User`. For more information on role-based authorization, see [role-based authorization documentation](../../security/authorization/roles.md). -## Enabling authentication in minimal apps +- **Claim-based strategies** determine a user's access based on claims issued by a central authority. For more information on claim-based authorization, see [claim-based authorization documentation](../../security/authorization/claims.md). -To enable authentication, call [`AddAuthentication`](/dotnet/api/microsoft.extensions.dependencyinjection.authenticationservicecollectionextensions.addauthentication) to register the required authentication services on the app's service provider. +In ASP.NET Core, both strategies are captured into an authorization requirement. The authorization service uses authorization handlers to determine whether or not a particular user meets the authorization requirements for a resource. + +## Enable authentication in minimal apps + +To enable authentication, call the [AddAuthentication](/dotnet/api/microsoft.extensions.dependencyinjection.authenticationservicecollectionextensions.addauthentication) method to register the required authentication services on the app's service provider. :::code language="csharp" source="~/fundamentals/minimal-apis/security/7.0-samples/MinApiAuth/MinApiAuth/Program.cs" id="snippet_1" highlight="2"::: -Typically, a specific authentication strategy is used. In the following sample, the app is configured with support for JWT bearer-based authentication. This example makes use of the APIs available in the [`Microsoft.AspNetCore.Authentication.JwtBearer`](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer) NuGet package. +Typically, a specific authentication strategy is used. In the following sample, the app is configured with support for JSON Web Token (JWT) bearer-based authentication. This example makes use of the APIs available in the [Microsoft.AspNetCore.Authentication.JwtBearer](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer) NuGet package. :::code language="csharp" source="~/fundamentals/minimal-apis/security/7.0-samples/MinApiAuth/MinApiAuth/Program.cs" id="snippet_jwt1" highlight="2-3"::: -By default, the [`WebApplication`](/dotnet/api/microsoft.aspnetcore.builder.webapplication) automatically registers the authentication and authorization middlewares if certain authentication and authorization services are enabled. In the following sample, it's not necessary to invoke [`UseAuthentication`](/dotnet/api/microsoft.aspnetcore.builder.authappbuilderextensions.useauthentication) or [`UseAuthorization`](/dotnet/api/microsoft.aspnetcore.builder.authorizationappbuilderextensions.useauthorization) to register the middlewares because [`WebApplication`](/dotnet/api/microsoft.aspnetcore.builder.webapplication) does this automatically after `AddAuthentication` or `AddAuthorization` are called. +By default, the [WebApplication](/dotnet/api/microsoft.aspnetcore.builder.webapplication) automatically registers the authentication and authorization middleware if certain authentication and authorization services are enabled. In the following sample, it's not necessary to invoke the [UseAuthentication](/dotnet/api/microsoft.aspnetcore.builder.authappbuilderextensions.useauthentication) or [UseAuthorization](/dotnet/api/microsoft.aspnetcore.builder.authorizationappbuilderextensions.useauthorization) methods to register the middleware. [WebApplication](/dotnet/api/microsoft.aspnetcore.builder.webapplication) automatically completes the registration after calling the `AddAuthentication` or `AddAuthorization` method. :::code language="csharp" source="~/fundamentals/minimal-apis/security/7.0-samples/MinApiAuth/MinApiAuth/Program.cs" id="snippet_jwt2"::: -In some cases, such as controlling middleware order, it's necessary to explicitly register authentication and authorization. In the following sample, the authentication middleware runs _after_ the CORS middleware has run. For more information on middlewares and this automatic behavior, see [Middleware in Minimal API apps](/aspnet/core/fundamentals/minimal-apis/middleware). +In some cases, such as controlling middleware order, it's necessary to explicitly register authentication and authorization. In the following sample, the authentication middleware runs _after_ the CORS middleware runs. For more information on middleware and this automatic behavior, see [Middleware in Minimal API apps](./middleware.md). :::code language="csharp" source="~/fundamentals/minimal-apis/security/7.0-samples/MinApiAuth/MinApiAuth/Program.cs" id="snippet_after" highlight="9-11"::: -### Configuring authentication strategy +### Configure authentication strategy -Authentication strategies typically support a variety of configurations that are loaded via options. Minimal apps support loading options from configuration for the following authentication strategies: +Authentication strategies typically support various configurations that are loaded via options. Minimal apps support loading options from configuration for the following authentication strategies: -* [JWT bearer-based](https://jwt.io/introduction) -* [OpenID Connection-based](https://openid.net/developers/how-connect-works/) +* [JWT bearer-based authentication](https://jwt.io/introduction#what-is-json-web-token) +* [OpenID Connect-based authentication](https://openid.net/developers/how-connect-works/) -The ASP.NET Core framework expects to find these options under the `Authentication:Schemes:{SchemeName}` section in [configuration](/aspnet/core/fundamentals/configuration). In the following sample, two different schemes, `Bearer` and `LocalAuthIssuer`, are defined with their respective options. The `Authentication:DefaultScheme` option can be used to configure the default authentication strategy that's used. +The ASP.NET Core framework expects to find these options under the `Authentication:Schemes:{SchemeName}` section in the [configuration](../configuration/index.md). In the following sample, two different schemes, `Bearer` and `LocalAuthIssuer`, are defined with their respective options. The `Authentication:DefaultScheme` option can be used to configure the default authentication strategy. ```json { @@ -80,63 +92,68 @@ The ASP.NET Core framework expects to find these options under the `Authenticati } ``` -In `Program.cs`, two JWT bearer-based authentication strategies are registered, with the: +In the _Program.cs_ file, two JWT bearer-based authentication strategies are registered with the following scheme names: -* "Bearer" scheme name. -* "LocalAuthIssuer" scheme name. +* "Bearer" +* "LocalAuthIssuer" -"Bearer" is the typical default scheme in JWT-bearer based enabled apps, but the default scheme can be overridden by setting the `DefaultScheme` property as in the preceding example. +"Bearer" is the typical default scheme in JWT-bearer based enabled apps. However, you can override the default scheme by setting the `DefaultScheme` property as shown in the previous example. -The scheme name is used to uniquely identify an authentication strategy and is used as the lookup key when resolving authentication options from config, as shown in the following example: +The scheme name is used to uniquely identify an authentication strategy. The name is also used as the lookup key when resolving authentication options from config, as shown in the following example: :::code language="csharp" source="~/fundamentals/minimal-apis/security/7.0-samples/MinApiAuth/MinApiAuth/Program.cs" id="snippet_local" highlight="5"::: -## Configuring authorization policies in minimal apps +## Configure authorization policies in minimal apps -Authentication is used to identify and validate the identity of users against an API. Authorization is used to validate and verify access to resources in an API and is facilitated by the `IAuthorizationService` registered by the `AddAuthorization` extension method. In the following scenario, a `/hello` resource is added that requires a user to present an `admin` role claim with a `greetings_api` scope claim. +Authentication identifies and validates the identity of users against an API. Authorization validates and verifies access to resources in an API. The `IAuthorizationService` service registered by the `AddAuthorization` extension method facilitates the authorization. In the following scenario, a `/hello` resource is added that requires a user to present an `admin` role claim with a `greetings_api` scope claim. -Configuring authorization requirements on a resource is a two-step process that requires: +Configuration of the authorization requirements on a resource is a two-step process: -1. Configuring the authorization requirements in a policy globally. -2. Applying individual policies to resources. +1. Define the authorization requirements in a policy globally. +1. Apply individual policies to resources. -In the following code, is invoked which: +In the following code, the method is invoked, which: * Adds authorization-related services to the DI container. -* Returns an that can be used to directly register authorization policies. +* Returns an object that can be used to directly register authorization policies. -The code creates a new authorization policy, named `admin_greetings`, that encapsulates two authorization requirements: +The code creates a new authorization policy named `admin_greetings` that encapsulates two authorization requirements: -* A role-based requirement via for users with an `admin` role. -* A claim-based requirement via that the user must provide a `greetings_api` scope claim. +* A role-based requirement via the for users with an `admin` role. +* A claim-based requirement via the for which the user must provide a `greetings_api` scope claim. -The `admin_greetings` policy is provided as a required policy to the `/hello` endpoint. +The `admin_greetings` policy is provided as a required policy to the `/hello` endpoint: :::code language="csharp" source="~/fundamentals/minimal-apis/security/7.0-samples/MinApiAuth/MinApiAuth/Program.cs" id="snippet_greet" highlight="5-9,13-14"::: -## Use `dotnet user-jwts` for development testing +## Use 'dotnet user-jwts' for development testing -Throughout this article, an app configured with JWT-bearer based authentication is used. JWT bearer-based authentication requires that clients present a token in the request header to validate their identity and claims. Typically, these tokens are issued by a central authority, such as an identity server. +The examples in this article use an app configured with JWT-bearer based authentication. JWT bearer-based authentication requires clients to present a token in the request header, which is used to validate their identity and claims. Typically, a central authority like an identity server issues the tokens. -When developing on the local machine, the [`dotnet user-jwts`](/aspnet/core/security/authentication/jwt-authn) tool can be used to create bearer tokens. +For development on the local machine, the [dotnet user-jwts](../../security/authentication/jwt-authn.md) command-line tool can be used to create bearer tokens. ```dotnetcli dotnet user-jwts create ``` > [!NOTE] -> When invoked on a project, the tool automatically adds the authentication options matching the generated token to `appsettings.json`. +> When invoked on a project, the tool automatically adds the authentication options that match the generated token to the _appsettings.json_ file. -Tokens can be configured with a variety of customizations. For example, to create a token for the `admin` role and `greetings_api` scope expected by the authorization policy in the preceding code: +Tokens can be configured with various customizations. For example, to create a token for the `admin` role and `greetings_api` scope expected by the authorization policy in the preceding code, run the tool as follows: ```dotnetcli dotnet user-jwts create --scope "greetings_api" --role "admin" ``` -The generated token can then be sent as part of the header in the testing tool of choice. For example, with curl: +The generated token can then be sent as part of the header in the testing tool of choice. For example, to send the token with curl: ```dotnetcli curl -i -H "Authorization: Bearer {token}" https://localhost:{port}/hello ``` -For more information on the `dotnet user-jwts` tool, read the [complete documentation](/aspnet/core/security/authentication/jwt-authn). +## Related content + +- [The authentication service (IAuthenticationService)](/dotnet/api/microsoft.aspnetcore.authentication.iauthenticationservice) +- [The authorization service (IAuthorizationService)](/dotnet/api/microsoft.aspnetcore.authorization.iauthorizationservice) +- [ASP.NET Core Middleware](./middleware.md) +- [Manage JSON Web Tokens with the dotnet user-jwts tool](../../security/authentication/jwt-authn.md) diff --git a/aspnetcore/host-and-deploy/visual-studio-publish-profiles.md b/aspnetcore/host-and-deploy/visual-studio-publish-profiles.md index 4b643d0d9bf0..100b52eb49c7 100644 --- a/aspnetcore/host-and-deploy/visual-studio-publish-profiles.md +++ b/aspnetcore/host-and-deploy/visual-studio-publish-profiles.md @@ -5,7 +5,7 @@ description: Learn how to create publish profiles in Visual Studio and use them monikerRange: '>= aspnetcore-2.1' ms.author: tdykstra ms.custom: mvc -ms.date: 07/28/2020 +ms.date: 04/27/2026 uid: host-and-deploy/visual-studio-publish-profiles --- # Visual Studio publish profiles (.pubxml) for ASP.NET Core app deployment @@ -60,7 +60,7 @@ The [Web SDK](xref:razor-pages/web-sdk) imports the [Razor SDK](xref:razor-pages To explicitly add a file to the publish list, add the file directly in the `.csproj` file as shown in the [Include Files](#include-files) section. -When selecting the **Publish** button in Visual Studio or when publishing from the command line: +When selecting the **Publish** button in Visual Studio, or when publishing from the command line: * The properties/items are computed (the files that are needed to build). * **Visual Studio only**: NuGet packages are restored. (Restore needs to be explicit by the user on the CLI.) @@ -135,7 +135,7 @@ The **Publish** tab of the app capabilities page is displayed. Several publish t * IIS, FTP, Web Deploy (for any web server) * Import Profile -To determine the most appropriate publish target, see [What publishing options are right for me](/visualstudio/ide/not-in-toc/web-publish-options). +To determine the most appropriate publish target, see [What publishing options are right for me](/visualstudio/deployment/deploying-applications-services-and-components-resources#what-publishing-options-are-right-for-me). When the **Folder** publish target is selected, specify a folder path to store the published assets. The default folder path is *bin\\{PROJECT CONFIGURATION}\\{TARGET FRAMEWORK MONIKER}\publish\\*. For example, *bin\Release\netcoreapp2.2\publish\\*. Select the **Create Profile** button to finish. @@ -149,7 +149,7 @@ Visual Studio's publish tool produces a `Properties/PublishProfiles/{PROFILE NAM When publishing to an Azure target, the *.pubxml* file: * Contains the Azure subscription identifier. -* Should not be checked into source control because the subscription identifier is sensitive information. +* Shouldn't be checked into source control because the subscription identifier is sensitive information. Sensitive information, for example, the publish password, is encrypted on a per user/machine level. The `Properties/PublishProfiles/{PROFILE NAME}.pubxml.user` file contains the information needed by MSBuild to retrieve the user name and password. diff --git a/aspnetcore/host-and-deploy/windows-service.md b/aspnetcore/host-and-deploy/windows-service.md index 127e6ac3e037..5dc3b4231fc6 100644 --- a/aspnetcore/host-and-deploy/windows-service.md +++ b/aspnetcore/host-and-deploy/windows-service.md @@ -5,7 +5,7 @@ description: Learn how to host an ASP.NET Core app in a Windows Service. monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra ms.custom: mvc -ms.date: 12/19/2022 +ms.date: 04/27/2026 uid: host-and-deploy/windows-service --- # Host ASP.NET Core in a Windows Service @@ -51,7 +51,7 @@ The following `Program.cs` calls [`AddHostedService`](/dotnet/api/microsoft.exte :::code language="csharp" source="~/host-and-deploy/windows-service/samples/7.x/WebAppServiceSample/Program.cs" highlight="8"::: -The following sample apps accompany this topic: +The following sample apps accompany this article: * Background Worker Service Sample: A non-web app sample based on the [Worker Service template](#worker-service-template) that uses [hosted services](xref:fundamentals/host/hosted-services) for background tasks. * Web App Service Sample: A Razor Pages web app sample that runs as a Windows Service with [hosted services](xref:fundamentals/host/hosted-services) for background tasks. @@ -102,7 +102,7 @@ A Windows [Runtime Identifier (RID)](/dotnet/core/rid-catalog) is included in th To publish for multiple RIDs: * Provide the RIDs in a semicolon-delimited list. -* Use the property name [\](/dotnet/core/tools/csproj#runtimeidentifiers) (plural). +* Use the property name [\](/dotnet/core/project-sdk/msbuild-props#runtimeidentifiers) (plural). For more information, see [.NET RID Catalog](/dotnet/core/rid-catalog). @@ -122,13 +122,13 @@ On Windows OS earlier than the Windows 10 October 2018 Update (version 1809/buil powershell -Command "New-LocalUser -Name {SERVICE NAME}" ``` -Provide a [strong password](/windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements) when prompted. +Provide a [strong password](/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements) when prompted. Unless the `-AccountExpires` parameter is supplied to the [New-LocalUser](/powershell/module/microsoft.powershell.localaccounts/new-localuser) cmdlet with an expiration , the account doesn't expire. -For more information, see [Microsoft.PowerShell.LocalAccounts](/powershell/module/microsoft.powershell.localaccounts/) and [Service User Accounts](/windows/desktop/services/service-user-accounts). +For more information, see [Microsoft.PowerShell.LocalAccounts](/powershell/module/microsoft.powershell.localaccounts/) and [Service User Accounts](/windows/win32/services/service-user-accounts). -An alternative approach to managing users when using Active Directory is to use Managed Service Accounts. For more information, see [Group Managed Service Accounts Overview](/windows-server/security/group-managed-service-accounts/group-managed-service-accounts-overview). +An alternative approach to managing users when using Active Directory is to use Managed Service Accounts. For more information, see [Group Managed Service Accounts Overview](/windows-server/identity/ad-ds/manage/group-managed-service-accounts/group-managed-service-accounts/group-managed-service-accounts-overview). ## Log on as a service rights @@ -280,7 +280,7 @@ Many startup errors don't produce useful information in the event logs. You can ### Clear package caches -A functioning app may fail immediately after upgrading either the .NET SDK on the development machine or changing package versions within the app. In some cases, incoherent packages may break an app when performing major upgrades. Most of these issues can be fixed by following these instructions: +A functioning app might fail immediately after upgrading either the .NET SDK on the development machine or changing package versions within the app. In some cases, incoherent packages might break an app when performing major upgrades. Most of these issues can be fixed by following these instructions: 1. Delete the *bin* and *obj* folders. 1. Clear the package caches by executing [dotnet nuget locals all --clear](/dotnet/core/tools/dotnet-nuget-locals) from a command shell. @@ -296,7 +296,7 @@ A *crash dump* is a snapshot of the system's memory and can help determine the c #### App crashes or encounters an exception -Obtain and analyze a dump from [Windows Error Reporting (WER)](/windows/desktop/wer/windows-error-reporting): +Obtain and analyze a dump from [Windows Error Reporting (WER)](/windows/win32/wer/windows-error-reporting): 1. Create a folder to hold crash dump files at `c:\dumps`. 1. Run the [EnableDumps PowerShell script](https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/host-and-deploy/windows-service/samples/scripts/EnableDumps.ps1) with the application executable name: diff --git a/aspnetcore/includes/route-groups.md b/aspnetcore/includes/route-groups.md index cd8181181d48..73af3f4a4f3e 100644 --- a/aspnetcore/includes/route-groups.md +++ b/aspnetcore/includes/route-groups.md @@ -1,4 +1,4 @@ -The extension method helps organize groups of endpoints with a common prefix. It reduces repetitive code and allows for customizing entire groups of endpoints with a single call to methods like and which add [endpoint metadata](xref:fundamentals/routing#endpoint-metadata). +The extension method helps organize groups of endpoints with a common prefix and reduces repetitive code. Use this method to customize entire groups of endpoints with a single call to methods like and that add [endpoint metadata](xref:fundamentals/routing#endpoint-metadata). For example, the following code creates two similar groups of endpoints: @@ -10,23 +10,23 @@ In this scenario, you can use a relative address for the `Location` header in th :::code language="csharp" source="~/fundamentals/minimal-apis/7.0-samples/todo-group/TodoEndpoints.cs" id="snippet_create"::: -The first group of endpoints will only match requests prefixed with `/public/todos` and are accessible without any authentication. The second group of endpoints will only match requests prefixed with `/private/todos` and require authentication. +The first group of endpoints matches only requests prefixed with `/public/todos` and are accessible without any authentication. The second group of endpoints matches only requests prefixed with `/private/todos` and require authentication. -The `QueryPrivateTodos` [endpoint filter factory](xref:fundamentals/minimal-apis/min-api-filters) is a local function that modifies the route handler's `TodoDb` parameters to allow to access and store private todo data. +`QueryPrivateTodos` is a local function that modifies the `TodoDb` parameters of the route handler, to enable them to access and store private todo data. `QueryPrivateTodos` serves as an [endpoint filter factory](xref:fundamentals/minimal-apis/min-api-filters). -Route groups also support nested groups and complex prefix patterns with route parameters and constraints. In the following example, and route handler mapped to the `user` group can capture the `{org}` and `{group}` route parameters defined in the outer group prefixes. +Route groups also support nested groups and complex prefix patterns with route parameters and constraints. In the following example, the route handler mapped to the `user` group can capture the `{org}` and `{group}` route parameters defined in the outer group prefixes. -The prefix can also be empty. This can be useful for adding endpoint metadata or filters to a group of endpoints without changing the route pattern. +The prefix can also be empty. This approach can be useful for adding endpoint metadata or filters to a group of endpoints without changing the route pattern. :::code language="csharp" source="~/fundamentals/minimal-apis/7.0-samples/todo-group/Program.cs" id="snippet_NestedMapGroup1"::: -Adding filters or metadata to a group behaves the same way as adding them individually to each endpoint before adding any extra filters or metadata that may have been added to an inner group or specific endpoint. +Adding filters or metadata to a group results in the same behavior as adding them individually to each endpoint (before adding extra filters or metadata that might exist in an inner group or specific endpoint). :::code language="csharp" source="~/fundamentals/minimal-apis/7.0-samples/todo-group/Program.cs" id="snippet_NestedMapGroup2"::: -In the above example, the outer filter will log the incoming request before the inner filter even though it was added second. Because the filters were applied to different groups, the order they were added relative to each other does not matter. The order filters are added does matter if applied to the same group or specific endpoint. +In the preceding example, the outer filter logs the incoming request before the inner filter even though the outer filter is added second. Because the filters are applied to different groups, the order that they're added relative to each other doesn't matter. The order in which filters are added matters when applied to the same group or specific endpoint. -A request to `/outer/inner/` will log the following: +A request to `/outer/inner/` logs the following data: ```dotnetcli /outer group filter diff --git a/aspnetcore/mvc/controllers/actions.md b/aspnetcore/mvc/controllers/actions.md index b6a4773197a6..796be15fc09d 100644 --- a/aspnetcore/mvc/controllers/actions.md +++ b/aspnetcore/mvc/controllers/actions.md @@ -3,7 +3,7 @@ title: Handle requests with controllers in ASP.NET Core MVC author: ardalis description: Learn how ASP.NET Core MVC controllers and Actions handle requests and return responses. ms.author: tdykstra -ms.date: 12/05/2019 +ms.date: 04/27/2026 uid: mvc/controllers/actions --- # Handle requests with controllers in ASP.NET Core MVC @@ -29,7 +29,7 @@ A controller is an instantiable class, usually [public](/dotnet/csharp/language- A controller class must not have an associated `[NonController]` attribute. -Controllers should follow the [Explicit Dependencies Principle](/dotnet/standard/modern-web-apps-azure-architecture/architectural-principles#explicit-dependencies). There are a couple of approaches to implementing this principle. If multiple controller actions require the same service, consider using [constructor injection](xref:mvc/controllers/dependency-injection#constructor-injection) to request those dependencies. If the service is needed by only a single action method, consider using [Action Injection](xref:mvc/controllers/dependency-injection#action-injection-with-fromservices) to request the dependency. +Controllers should follow the [Explicit Dependencies Principle](/dotnet/architecture/modern-web-apps-azure/architectural-principles#explicit-dependencies). There are a couple of approaches to implementing this principle. If multiple controller actions require the same service, consider using [constructor injection](xref:mvc/controllers/dependency-injection#constructor-injection) to request those dependencies. If the service is needed by only a single action method, consider using [Action Injection](xref:mvc/controllers/dependency-injection#action-injection-with-fromservices) to request the dependency. Within the **M**odel-**V**iew-**C**ontroller pattern, a controller is responsible for the initial processing of the request and instantiation of the model. Generally, business decisions should be performed within the model. @@ -43,7 +43,7 @@ Public methods on a controller, except those with the `[NonAction]` attribute, a Action methods should contain logic for mapping a request to a business concern. Business concerns should typically be represented as services that the controller accesses through [dependency injection](xref:mvc/controllers/dependency-injection). Actions then map the result of the business action to an application state. -Actions can return anything, but frequently return an instance of `IActionResult` (or `Task` for async methods) that produces a response. The action method is responsible for choosing *what kind of response*. The action result *does the responding*. +Actions can return anything, but they frequently return an instance of `IActionResult` (or `Task` for async methods) that produces a response. The action method is responsible for choosing *what kind of response*. The action result *does the responding*. ### Controller Helper Methods @@ -73,12 +73,12 @@ There are two result types within this category: [View](xref:mvc/views/overview) * **View** - This type returns a view which uses a model to render HTML. For example, `return View(customer);` passes a model to the view for data-binding. + This type returns a view, which uses a model to render HTML. For example, `return View(customer);` passes a model to the view for data-binding. * **Formatted Response** This type returns JSON or a similar data exchange format to represent an object in a specific manner. For example, `return Json(customer);` serializes the provided object into JSON format. - + Other common methods of this type include `File` and `PhysicalFile`. For example, `return PhysicalFile(customerFilePath, "text/xml");` returns . #### 3. Methods resulting in a non-empty response body formatted in a content type negotiated with the client @@ -94,6 +94,7 @@ Applications typically share parts of their workflow. Examples include an app th Most filter attributes, such as `[Authorize]`, can be applied at the controller or action level depending upon the desired level of granularity. Error handling and response caching are often cross-cutting concerns: + * [Handle errors](xref:mvc/controllers/filters#exception-filters) * [Response Caching](xref:performance/caching/response) diff --git a/aspnetcore/mvc/controllers/filters.md b/aspnetcore/mvc/controllers/filters.md index 8fcc979c0b20..39c48c7b2e8b 100644 --- a/aspnetcore/mvc/controllers/filters.md +++ b/aspnetcore/mvc/controllers/filters.md @@ -5,7 +5,7 @@ description: Learn how filters work and how to use them in ASP.NET Core. monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra ms.custom: mvc -ms.date: 6/20/2023 +ms.date: 04/28/2026 uid: mvc/controllers/filters --- # Filters in ASP.NET Core @@ -46,7 +46,7 @@ Each filter type is executed at a different stage in the filter pipeline: * Run first. * Determine whether the user is authorized for the request. - * Short-circuit the pipeline if the request is not authorized. + * Short-circuit the pipeline if the request isn't authorized. * [Resource filters](#resource-filters): @@ -73,7 +73,7 @@ Each filter type is executed at a different stage in the filter pipeline: * Apply global policies to unhandled exceptions that occur before the response body has been written to. * Run after model binding and action filters, but before the action result is executed. * Run only if an unhandled exception occurs during action execution or action result execution. - * Do not run for exceptions thrown during middleware execution, routing, or model binding. + * Don't run for exceptions thrown during middleware execution, routing, or model binding. * [Result filters](#result-filters): @@ -119,7 +119,7 @@ Attributes allow filters to accept arguments, as shown in the preceding example. :::code language="csharp" source="~/mvc/controllers/filters/samples/8.x/FiltersSample/Controllers/ResponseHeaderController.cs" id="snippet_ClassIndex" highlight="1"::: -Use a tool such as the [browser developer tools](https://developer.mozilla.org/docs/Learn/Common_questions/What_are_browser_developer_tools) to examine the headers. Under **Response Headers**, `filter-header: Filter Value` is displayed. +Use a tool such as the [browser developer tools](https://developer.mozilla.org/docs/Learn_web_development/Howto/Tools_and_setup/What_are_browser_developer_tools) to examine the headers. Under **Response Headers**, `filter-header: Filter Value` is displayed. The following code applies `ResponseHeaderAttribute` to both a controller and an action: @@ -141,14 +141,14 @@ Filter attributes: * * -Filters cannot be applied to Razor Page handler methods. They can be applied either to the Razor Page model or globally. +Filters can't be applied to Razor Page handler methods. They can be applied either to the Razor Page model or globally. ## Filter scopes and order of execution A filter can be added to the pipeline at one of three *scopes*: * Using an attribute on a controller or Razor Page. -* Using an attribute on a controller action. Filter attributes cannot be applied to Razor Pages handler methods. +* Using an attribute on a controller action. Filter attributes can't be applied to Razor Pages handler methods. * Globally for all controllers, actions, and Razor Pages as shown in the following code: :::code language="csharp" source="~/mvc/controllers/filters/samples/8.x/FiltersSample/Program.cs" id="snippet_GlobalFilter" highlight="6"::: @@ -244,7 +244,7 @@ Filters can be added by type or by instance. If an instance is added, that insta * An instance is created for each request. * Any constructor dependencies are populated by [dependency injection](xref:fundamentals/dependency-injection) (DI). -Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by [dependency injection](xref:fundamentals/dependency-injection) (DI). Constructor dependencies cannot be provided by DI because attributes must have their constructor parameters supplied where they're applied. +Filters that are implemented as attributes and added directly to controller classes or action methods can't have constructor dependencies provided by [dependency injection](xref:fundamentals/dependency-injection) (DI). Constructor dependencies can't be provided by DI because attributes must have their constructor parameters supplied where they're applied. The following filters support constructor dependencies provided from DI: @@ -277,9 +277,9 @@ In the following code, the `ServiceFilter` attribute retrieves an instance of th When using `ServiceFilterAttribute`, setting : -* Provides a hint that the filter instance *may* be reused outside of the request scope it was created within. The ASP.NET Core runtime doesn't guarantee: +* Provides a hint that the filter instance *might* be reused outside of the request scope it was created within. The ASP.NET Core runtime doesn't guarantee: * That a single instance of the filter will be created. - * The filter will not be re-requested from the DI container at some later point. + * The filter won't be re-requested from the DI container at some later point. * Shouldn't be used with a filter that depends on services with a lifetime other than singleton. implements . `IFilterFactory` exposes the method for creating an instance. `CreateInstance` loads the specified type from DI. @@ -294,9 +294,10 @@ Because `TypeFilterAttribute` types aren't resolved directly from the DI contain * `TypeFilterAttribute` can optionally accept constructor arguments for the type. When using `TypeFilterAttribute`, setting : -* Provides hint that the filter instance *may* be reused outside of the request scope it was created within. The ASP.NET Core runtime provides no guarantees that a single instance of the filter will be created. -* Should not be used with a filter that depends on services with a lifetime other than singleton. +* Provides hint that the filter instance *might* be reused outside of the request scope it was created within. The ASP.NET Core runtime provides no guarantees that a single instance of the filter will be created. + +* Shouldn't be used with a filter that depends on services with a lifetime other than singleton. The following example shows how to pass arguments to a type using `TypeFilterAttribute`: @@ -313,12 +314,12 @@ Authorization filters: Custom authorization filters require a custom authorization framework. Prefer configuring the authorization policies or writing a custom authorization policy over writing a custom filter. The built-in authorization filter: * Calls the authorization system. -* Does not authorize requests. +* Doesn't authorize requests. Do **not** throw exceptions within authorization filters: -* The exception will not be handled. -* Exception filters will not handle the exception. +* The exception won't be handled. +* Exception filters won't handle the exception. Consider issuing a challenge when an exception occurs in an authorization filter. @@ -357,9 +358,9 @@ The following code shows a sample action filter: The provides the following properties: -* - enables reading the inputs to an action method. -* - enables manipulating the controller instance. -* - setting `Result` short-circuits execution of the action method and subsequent action filters. +* : Enables reading the inputs to an action method. +* : Enables manipulating the controller instance. +* : Setting `Result` short-circuits execution of the action method and subsequent action filters. Throwing an exception in an action method: @@ -368,8 +369,8 @@ Throwing an exception in an action method: The provides `Controller` and `Result` plus the following properties: -* - True if the action execution was short-circuited by another filter. -* - Non-null if the action or a previously run action filter threw an exception. Setting this property to null: +* : True if another filter short-circuited the action execution. +* : Non-null if the action or a previously run action filter threw an exception. Setting this property to null: * Effectively handles the exception. * `Result` is executed as if it was returned from the action method. @@ -395,7 +396,7 @@ The `OnActionExecuting` action filter can be used to: The `OnActionExecuted` method runs after the action method: * And can see and manipulate the results of the action through the property. -* is set to true if the action execution was short-circuited by another filter. +* is set to true if another filter short-circuited the action execution. * is set to a non-null value if the action or a subsequent action filter threw an exception. Setting `Exception` to null: * Effectively handles an exception. * `ActionExecutedContext.Result` is executed as if it were returned normally from the action method. @@ -427,7 +428,7 @@ To handle an exception, set the being executed. An API method might perform some serialization as part of the execution of the result. Learn more about [action results](xref:mvc/controllers/actions). -Result filters are only executed when an action or action filter produces an action result. Result filters are not executed when: +Result filters are only executed when an action or action filter produces an action result. Result filters aren't executed when: * An authorization filter or resource filter short-circuits the pipeline. * An exception filter handles an exception by producing an action result. @@ -458,11 +459,11 @@ The method runs, the response has probably already been sent to the client. If the response has already been sent to the client, it cannot be changed. +When the method runs, the response has probably already been sent to the client. If the response has already been sent to the client, it can't be changed. -`ResultExecutedContext.Canceled` is set to `true` if the action result execution was short-circuited by another filter. +`ResultExecutedContext.Canceled` is set to `true` if another filter short-circuited the action result execution. -`ResultExecutedContext.Exception` is set to a non-null value if the action result or a subsequent result filter threw an exception. Setting `Exception` to null effectively handles an exception and prevents the exception from being thrown again later in the pipeline. There is no reliable way to write data to a response when handling an exception in a result filter. If the headers have been flushed to the client when an action result throws an exception, there's no reliable mechanism to send a failure code. +`ResultExecutedContext.Exception` is set to a non-null value if the action result or a subsequent result filter threw an exception. Setting `Exception` to null effectively handles an exception and prevents the exception from being thrown again later in the pipeline. There's no reliable way to write data to a response when handling an exception in a result filter. If the headers have been flushed to the client when an action result throws an exception, there's no reliable mechanism to send a failure code. For an , a call to `await next` on the executes any subsequent result filters and the action result. To short-circuit, set to `true` and don't call the `ResultExecutionDelegate`: @@ -487,15 +488,15 @@ For example, the following filter always runs and sets an action result ( [!WARNING] +> [!WARNING] > Only configure to return `true` if the source of the filters is unambiguous, the filters are stateless, and the filters are safe to use across multiple HTTP requests. For instance, don't return filters from DI that are registered as scoped or transient if `IFilterFactory.IsReusable` returns `true`. `IFilterFactory` can be implemented using custom attribute implementations as another approach to creating filters: diff --git a/aspnetcore/mvc/models/file-uploads.md b/aspnetcore/mvc/models/file-uploads.md index 1adef0257d10..c58109e99297 100644 --- a/aspnetcore/mvc/models/file-uploads.md +++ b/aspnetcore/mvc/models/file-uploads.md @@ -5,7 +5,7 @@ description: How to use model binding and streaming to upload files in ASP.NET C monikerRange: '>= aspnetcore-2.1' ms.author: tdykstra ms.custom: mvc -ms.date: 08/21/2020 +ms.date: 04/28/2026 uid: mvc/models/file-uploads --- # Upload files in ASP.NET Core @@ -20,7 +20,7 @@ ASP.NET Core supports uploading one or more files using buffered model binding f ## Security considerations -Use caution when providing users with the ability to upload files to a server. Cyberattackers may attempt to: +Use caution when providing users with the ability to upload files to a server. Cyberattackers might attempt to: * Execute [denial of service](/windows-hardware/drivers/ifs/denial-of-service) attacks. * Upload viruses or malware. @@ -34,7 +34,7 @@ Security steps that reduce the likelihood of a successful attack are: * Allow only approved file extensions for the app's design specification.† * Verify that client-side checks are performed on the server.† Client-side checks are easy to circumvent. * Check the size of an uploaded file. Set a maximum size limit to prevent large uploads.† -* When files shouldn't be overwritten by an uploaded file with the same name, check the file name against the database or physical storage before uploading the file. +* When an uploaded file shouldn't overwrite files with the same name. Check the file name against the database or physical storage before uploading the file. * **Run a virus/malware scanner on uploaded content before the file is stored.** †The sample app demonstrates an approach that meets the criteria. @@ -67,12 +67,12 @@ Common storage options for files include: * Physical storage (file system or network share) * For large file uploads: - * Database limits may restrict the size of the upload. + * Database limits might restrict the size of the upload. * Physical storage is often less economical than storage in a database. * Physical storage is potentially less expensive than using a cloud data storage service. * The app's process must have read and write permissions to the storage location. **Never grant execute permission.** -* Cloud data storage service, for example, [Azure Blob Storage](https://azure.microsoft.com/services/storage/blobs/). +* Cloud data storage service, for example, [Azure Blob Storage](https://azure.microsoft.com/products/storage/blobs/). * Services usually offer improved scalability and resiliency over on-premises solutions that are usually subject to single points of failure. * Services are potentially lower cost in large storage infrastructure scenarios. @@ -99,22 +99,22 @@ For more information on , s Two general approaches for uploading files are buffering and streaming. -**Buffering** +### Buffering -The entire file is read into an . `IFormFile` is a C# representation of the file used to process or save the file. +The entire file is read into an . `IFormFile` is a C# representation of the file used to process or save the file. The disk and memory used by file uploads depend on the number and size of concurrent file uploads. If an app attempts to buffer too many uploads, the site crashes when it runs out of memory or disk space. If the size or frequency of file uploads is exhausting app resources, use streaming. Any single buffered file exceeding 64 KB is moved from memory to a temp file on disk. -Temporary files for larger requests are written to the location named in the `ASPNETCORE_TEMP` environment variable. If `ASPNETCORE_TEMP` is not defined, the files are written to the current user's temporary folder. +Temporary files for larger requests are written to the location named in the `ASPNETCORE_TEMP` environment variable. If `ASPNETCORE_TEMP` isn't defined, the files are written to the current user's temporary folder. -Buffering small files is covered in the following sections of this topic: +Buffering small files is covered in the following sections of this article: * [Physical storage](#upload-small-files-with-buffered-model-binding-to-physical-storage) * [Database](#upload-small-files-with-buffered-model-binding-to-a-database) -**Streaming** +### Streaming The file is received from a multipart request and directly processed or saved by the app. Streaming doesn't improve performance significantly. Streaming reduces the demands for memory or disk space when uploading files. @@ -191,9 +191,9 @@ The following example is analogous to the prior example except that: ``` -To perform the form POST in JavaScript for clients that [don't support the Fetch API](https://caniuse.com/#feat=fetch), use one of the following approaches: +To perform the form POST in JavaScript for clients that [don't support the Fetch API](https://caniuse.com/fetch), use one of the following approaches: -* Use a Fetch Polyfill (for example, [window.fetch polyfill (github/fetch)](https://github.com/github/fetch)). +* Use a Fetch Polyfill (for example, [window.fetch polyfill (github/fetch)](https://github.com/JakeChampion/fetch)). * Use `XMLHttpRequest`. For example: ```javascript @@ -256,7 +256,7 @@ When uploading files using model binding and *must* include the file name. If the file name isn't provided, an is thrown at runtime. -Files uploaded using the technique are buffered in memory or on disk on the server before processing. Inside the action method, the contents are accessible as a . In addition to the local file system, files can be saved to a network share or to a file storage service, such as [Azure Blob storage](/azure/visual-studio/vs-storage-aspnet5-getting-started-blobs). +Files uploaded using the technique are buffered in memory or on disk on the server before processing. Inside the action method, the contents are accessible as a . In addition to the local file system, files can be saved to a network share or to a file storage service, such as [Azure Blob storage](/azure/storage/blobs/storage-quickstart-blobs-dotnet). For another example that loops over multiple files for upload and uses safe file names, see `Pages/BufferedMultipleFileUploadPhysical.cshtml.cs` in the sample app. > [!WARNING] > In .NET 7 or earlier versions, [Path.GetTempFileName](xref:System.IO.Path.GetTempFileName%2A) throws an when more than 65,535 files are created without deleting previous temporary files. The limit of 65,535 files is a per-server limit. For more information on this limit on Windows OS, see the remarks in the following articles: > -> * [GetTempFileNameA function](/windows/desktop/api/fileapi/nf-fileapi-gettempfilenamea#remarks) +> * [GetTempFileNameA function](/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea#remarks) > * ### Upload small files with buffered model binding to a database -To store binary file data in a database using [Entity Framework](/ef/core/index), define a array property on the entity: +To store binary file data in a database using [Entity Framework](/ef/core), define a array property on the entity: ```csharp public class AppFile @@ -404,7 +404,7 @@ The preceding example is similar to a scenario demonstrated in the sample app: * `Pages/BufferedSingleFileUploadDb.cshtml.cs` > [!WARNING] -> Use caution when storing binary data in relational databases, as it can adversely impact performance. +> Use caution when storing binary data in relational databases, as it can adversely affect performance. > > Don't rely on or trust the `FileName` property of without validation. The `FileName` property should only be used for display purposes and only after HTML encoding. > @@ -456,7 +456,7 @@ return Results.Ok($"Saved file at {filePath}"); For advanced scenarios, manually parse the raw request body using , which exposes an [`IPipeReader`](/aspnet/core/fundamentals/middleware/request-response) for low-level, high-performance streaming. The sample app includes endpoint handlers that use `IPipeReader` in both Minimal APIs and controllers. -The [3.1 example](https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/mvc/models/file-uploads/samples/3.x/SampleApp/Pages/StreamedSingleFileUploadDb.cshtml) demonstrates how to use JavaScript to stream a file to a controller action. The file's antiforgery token is generated using a custom filter attribute and passed to the client HTTP headers instead of in the request body. Because the action method processes the uploaded data directly, form model binding is disabled by another custom filter. Within the action, the form's contents are read using a `MultipartReader`, which reads each individual `MultipartSection`, processing the file or storing the contents as appropriate. After the multipart sections are read, the action performs its own model binding. +The [3.1 example](https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/mvc/models/file-uploads/samples/3.x/SampleApp/Pages/StreamedSingleFileUploadDb.cshtml) demonstrates how to use JavaScript to stream a file to a controller action. The file's antiforgery token is generated using a custom filter attribute and passed to the client HTTP headers instead of in the request body. Because the action method processes the uploaded data directly, another customer filter disables form model binding. Within the action, the form's contents are read using a `MultipartReader`, which reads each individual `MultipartSection`, processing the file or storing the contents as appropriate. After the multipart sections are read, the action performs its own model binding. The initial page response loads the form and saves an antiforgery token in a cookie (via the `GenerateAntiforgeryTokenCookieAttribute` attribute). The attribute uses ASP.NET Core's built-in [antiforgery support](xref:security/anti-request-forgery) to set a cookie with a request token: @@ -484,7 +484,7 @@ The complete `StreamingController.UploadPhysical` method for streaming to a phys [!code-csharp[](file-uploads/samples/3.x/SampleApp/Controllers/StreamingController.cs?name=snippet_UploadPhysical)] -In the sample app, validation checks are handled by `FileHelpers.ProcessStreamedFile`. +In the sample app, `FileHelpers.ProcessStreamedFile` handles validation checks. ## Validation @@ -493,7 +493,7 @@ The sample app's `FileHelpers` class demonstrates several checks for buffered [!WARNING] > The validation processing methods demonstrated in the sample app don't scan the content of uploaded files. In most production scenarios, a virus/malware scanner API is used on the file before making the file available to users or other systems. > -> Although the topic sample provides a working example of validation techniques, don't implement the `FileHelpers` class in a production app unless you: +> Although the article sample provides a working example of validation techniques, don't implement the `FileHelpers` class in a production app unless you: > > * Fully understand the implementation. > * Modify the implementation as appropriate for the app's environment and specifications. @@ -523,7 +523,7 @@ if (string.IsNullOrEmpty(ext) || !permittedExtensions.Contains(ext)) ### File signature validation -A file's signature is determined by the first few bytes at the start of a file. These bytes can be used to indicate if the extension matches the content of the file. The sample app checks file signatures for a few common file types. In the following example, the file signature for a JPEG image is checked against the file: +The first few bytes at the start of a file determine a file's signature. These bytes can be used to indicate if the extension matches the content of the file. The sample app checks file signatures for a few common file types. In the following example, the file signature for a JPEG image is checked against the file: ```csharp private static readonly Dictionary> _fileSignature = @@ -548,7 +548,7 @@ using (var reader = new BinaryReader(uploadedFileData)) } ``` -To obtain additional file signatures, use a [file signatures database (Google search result)](https://www.google.com/search?q=file+signatures+databases) and official file specifications. Consulting official file specifications may ensure that the selected signatures are valid. +To obtain additional file signatures, use a [file signatures database (Google search result)](https://www.google.com/search?q=file+signatures+databases) and official file specifications. Consulting official file specifications might ensure that the selected signatures are valid. ### File name security @@ -568,7 +568,7 @@ Razor automatically HTML encodes property values for display. The following code Outside of Razor, always file name content from a user's request. -Many implementations must include a check that the file exists; otherwise, the file is overwritten by a file of the same name. Supply additional logic to meet your app's specifications. +Many implementations must include a check that the file exists; otherwise, a file of the same name overwrites the file. Supply additional logic to meet your app's specifications. ### Size validation @@ -744,7 +744,7 @@ The `RequestSizeLimitAttribute` can also be applied using the [`@attribute`](xre ### Other Kestrel limits -Other Kestrel limits may apply for apps hosted by Kestrel: +Other Kestrel limits might apply for apps hosted by Kestrel: * [Maximum client connections](xref:fundamentals/servers/kestrel/options#maximum-client-connections) * [Request and response data rates](xref:fundamentals/servers/kestrel/options#minimum-request-body-data-rate) @@ -767,7 +767,7 @@ The `maxAllowedContentLength` setting only applies to IIS. For more information, ## Troubleshoot -Below are some common problems encountered when working with uploading files and their possible solutions. +Following are some common problems encountered when working with uploading files and their possible solutions. ### Not Found error when deployed to an IIS server @@ -782,7 +782,7 @@ For more information, see the [IIS](#iis) section. ### Connection failure -A connection error and a reset server connection probably indicates that the uploaded file exceeds Kestrel's maximum request body size. For more information, see the [Kestrel maximum request body size](#kestrel-maximum-request-body-size) section. Kestrel client connection limits may also require adjustment. +A connection error and a reset server connection probably indicate that the uploaded file exceeds Kestrel's maximum request body size. For more information, see the [Kestrel maximum request body size](#kestrel-maximum-request-body-size) section. Kestrel client connection limits might also require adjustment. ### Null Reference Exception with IFormFile @@ -790,7 +790,7 @@ If the controller is accepting uploaded files using to hold the uploaded file's content. The size limit of a `MemoryStream` is `int.MaxValue`. If the app's file upload scenario requires holding file content larger than 50 MB, use an alternative approach that doesn't rely upon a single `MemoryStream` for holding an uploaded file's content. +The examples in this article rely upon to hold the uploaded file's content. The size limit of a `MemoryStream` is `int.MaxValue`. If the app's file upload scenario requires holding file content larger than 50 MB, use an alternative approach that doesn't rely upon a single `MemoryStream` for holding an uploaded file's content. :::moniker-end @@ -2259,14 +2259,17 @@ The examples in this topic rely upon to hold the u :::moniker-end - ## Additional resources :::moniker range="< aspnetcore-5.0" + * [HTTP connection request draining](xref:fundamentals/servers/kestrel#http11-request-draining) + :::moniker-end :::moniker range=">= aspnetcore-5.0" + * [HTTP connection request draining](xref:fundamentals/servers/kestrel/request-draining) + :::moniker-end * [Unrestricted File Upload](https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload)