Chapter 7: Model binding and validation in minimal APIs
This chapter introduces model binding in minimal APIs as the process that turns HTTP request data into handler inputs, then validates that user-provided input is acceptable.
After this chapter you will be able to
- Model binding purpose. Explain model binding as the process of taking raw values from an HTTP request and making them available to minimal API endpoint handlers by populating POCOs or handler arguments.
- Request data as handler input. Describe how model binding can bind data posted in the request body or supplied in the URL to C# objects that are passed as arguments to endpoint handler methods.
- Model binding purpose. Explain that model binding extracts values from an HTTP request, creates appropriately typed .NET objects, and supplies them as parameters when a minimal API endpoint handler is called.
- Binding pipeline timing. Trace that RoutingMiddleware selects an endpoint and extracts route values as strings, while EndpointMiddleware performs model binding before the filter pipeline and endpoint handler execute.
- Minimal API binding sources. Describe the six binding sources available to minimal API handler parameters: route values, query-string values, header values, a JSON request body, dependency-injected services, and custom binding; distinguish JSON body binding from automatic form binding.
- Convention-based simple binding. Explain how ASP.NET Core chooses between a route value and a query-string value when binding a simple handler parameter. State that a parameter name matching a route-template parameter binds from the route; otherwise ASP.NET Core looks for a query-string value.
- Explicit simple binding sources. Describe how [FromRoute], [FromQuery], and [FromHeader] force a simple handler parameter to bind from a particular request source. State that these attributes override the default inference, and that headers require [FromHeader] rather than convention-based binding.
- Custom simple types. Explain how a custom type can participate in simple-type binding by exposing one of the supported TryParse methods. Describe that ASP.NET Core calls TryParse on the incoming route, query-string, or header text; a false result means binding fails and returns 400 Bad Request.
- Complex JSON body binding. Explain how a minimal API binds a JSON request body to a single complex handler parameter. State that ASP.NET Core uses System.Text.Json to deserialize valid JSON into an instance, such as a Product argument, before the handler runs.
- Body-binding restrictions and errors. Distinguish the restrictions on JSON body binding in minimal APIs: only one handler parameter can bind from the body, and a non-JSON body produces a 415 Unsupported Media Type response without running the handler. Describe why binding a body for verbs that do not usually send one, including GET, causes a runtime exception, and how [FromBody] can override that behavior but is discouraged for GET requests.
- Repeated query value arrays. Describe why a repeated query-string key such as ?id=123&id=456 cannot bind to a single int parameter, and how an int[] parameter binds all of those values instead.
- Array binding source rules. Distinguish the conditions under which an array binds from repeated URL values versus the JSON body: only simple-type arrays, string[], or StringValues on body-less verbs such as GET, HEAD, and DELETE get the repeated-value behavior; otherwise ASP.NET Core attempts JSON body binding.
- Required parameter binding. Explain what happens when a required minimal API handler parameter cannot be bound from its request source. State that this applies to route values, query strings, headers, and request bodies.
- Nullable optional parameters. Describe how marking a handler parameter nullable makes it optional and causes a missing bound value to be supplied as null. Distinguish nullable value types such as int? from nullable reference-type annotations for complex JSON-body types.
- Special parameter categories. Describe the three categories of special types available as minimal API endpoint-handler parameters: well-known framework types, file-upload types, and application services. Explain that these differ from values created by binding ordinary request data.
- Well-known handler type injection. Explain that a minimal API endpoint handler can receive a well-known type by declaring a parameter of that type. Describe HttpContext as the object containing the low-level details of one request and its response, including services and features.
- Request type shortcuts. Describe the well-known types that are shortcuts to HttpContext properties: HttpRequest, HttpResponse, CancellationToken, ClaimsPrincipal, Stream, and PipeReader. Distinguish their purposes, including cancellation after a client aborts and efficient processing of large request bodies with Stream or PipeReader.
- Automatic service injection. Explain that a registered service can be declared as a parameter of a minimal API endpoint handler and ASP.NET Core injects an instance from the DI container automatically.
- File upload parameter binding. Describe how a minimal API endpoint accepts one uploaded file with IFormFile or multiple uploaded files with IFormFileCollection, and explain how the handler reads an uploaded file's contents.
- File upload security precautions. Explain why uploaded files must be treated as potentially malicious, including why an application must not trust the supplied FileName and should generate a new name before saving a file.
- Buffered upload size limits. Explain why IFormFile is appropriate for small uploads but unsuitable for large uploads: ASP.NET Core buffers the entire file in memory and on disk before the handler receives it, whereas large uploads may need direct streaming.
- BindAsync custom model binding. Explain how implementing a static BindAsync method on an endpoint parameter type enables completely custom model binding in a minimal API. Describe that BindAsync receives HttpContext, can extract needed request data, and can use either the simpler signature or a signature that also receives parameter reflection details.
- Binding failure response behavior. Describe the outcome when BindAsync returns null for a required endpoint parameter: EndpointMiddleware throws BadHttpRequestException and produces a 400 response. Distinguish this from throwing an exception inside BindAsync, which EndpointMiddleware does not catch and which results in a 500 response.
- Binding-source precedence order. Explain the order in which minimal APIs choose a binding source for each handler parameter. Describe that the infrastructure stops at the first applicable source, including the precedence of explicit attributes, well-known types, BindAsync, simple-type route or query binding, simple arrays on bodyless verbs, DI services, and finally JSON-body binding.
- AsParameters handler grouping. Explain how the [AsParameters] attribute wraps multiple endpoint-handler arguments in a single class, record, struct, or record struct to simplify an unwieldy minimal API handler signature.
- Binding rules for grouped types. Describe how constructor parameters or properties of an [AsParameters] type follow the same binding attributes and rules as ordinary endpoint-handler parameters, including [From*] attributes, services and well-known types, and body data.
- Validation purpose and necessity. Explain what validation is for in an application and why every app needs to add it when handling user input.
- Minimal API validation approach. Describe the validation approach in minimal APIs: validation is not included by default, and the framework supplies nonprescriptive filter hooks so applications can choose how to add it.
- Untrusted request input. Explain why values sent in an HTTP request must be treated as untrusted and validated before the endpoint uses them.
- Early validation timing. Describe when validation should happen in a minimal API: before endpoint handler parameters are used to touch the domain, infrastructure, or information that could be exposed to an attacker, preferably as early as possible in the filter pipeline.
- DataAnnotations validation metadata. Explain how DataAnnotations attributes decorate a parameter type with metadata that specifies the acceptable state of its bound properties, rather than supplying the property data itself. Describe examples such as requiring a value, limiting a string length, constraining a numeric range, and validating an email-format field.
- Cross-property validation rules. Explain that IValidatableObject and its Validate method can add model-level validation when a rule depends on multiple properties, such as requiring an email address or phone number. Describe its limitations: Validate has no easy access to application services and runs only after all DataAnnotations attribute conditions succeed.
- Validation execution requirement. State that adding DataAnnotations or IValidatableObject rules only declares validation metadata and does not itself validate a minimal API request or return an error. Explain that minimal APIs need code to read the metadata, test the bound model, and return an error response; the next section adds this through a validation filter and a small NuGet package.
- Minimal API validation approach. Explain why minimal APIs typically use endpoint filters for validation rather than built-in dedicated validation APIs. State that Microsoft left validation flexible and optional for performance, and that every endpoint must validate incoming data using DataAnnotations or another approach.
- WithParameterValidation filter behavior. Describe how to install MinimalApis.Extensions and add WithParameterValidation() to an endpoint to validate a complex parameter. Trace that the model is bound from the JSON body first, valid input proceeds to the handler, and invalid input produces a 400 Bad Request Problem Details response describing the errors.
What it builds on
- Defining route handlers with functions (chapter 5) · Endpoint handlers are defined as functions that receive arguments.
- Working with parameters and literal segments (chapter 6) · Routes can contain parameter values extracted from URL segments.
- Extracting values from the URL with routing (chapter 5) · Minimal API endpoints can extract values from URLs using routing.
- Running common code with endpoint filters (chapter 5) · Endpoint filters provide a way to run common logic around endpoint handling.
- Simple pipeline scenario 3: A minimal API application (chapter 4) · Minimal API applications process requests through middleware.
- Endpoint routing in ASP.NET Core (chapter 6) · Endpoint routing matches requests to endpoints.
- Returning other data types (chapter 5) · Minimal APIs can return data types that are serialized into HTTP responses.
- Mapping verbs to endpoints (chapter 5) · Endpoints are mapped to HTTP verbs such as GET and POST.
Section by section
Introduction
This chapter introduces model binding in minimal APIs as the process that turns HTTP request data into handler inputs, then validates that user-provided input is acceptable.
- Model binding purpose: Explain model binding as the process of taking raw values from an HTTP request and making them available to minimal API endpoint handlers by populating POCOs or handler arguments.
Why it matters: Model binding lets endpoint code work with C# values instead of manually parsing incoming HTTP requests. - Request data as handler input: Describe how model binding can bind data posted in the request body or supplied in the URL to C# objects that are passed as arguments to endpoint handler methods.
Why it matters: An endpoint can use bound request values to perform work such as retrieving product details or changing a product name. - User input validation need: Justify validating values supplied by users after model binding: bound data originates with users, so an application must ensure it is valid and makes sense before relying on it.
Why it matters: Binding makes input convenient to use, but validation helps prevent an application from acting on unsuitable user-provided values.
Key terms: model binding, HTTP request, POCO, endpoint handler, binding model, request body, URL, JSON, C# objects, endpoint handler methods
7.1 Extracting values from a request with model binding
Introduces model binding as the minimal API process that creates endpoint-handler arguments from HTTP request data before filters and handlers run.
- Model binding purpose: Explain that model binding extracts values from an HTTP request, creates appropriately typed .NET objects, and supplies them as parameters when a minimal API endpoint handler is called.
Why it matters: Model binding lets handlers declare the data they need as normal C# parameters instead of manually reading and converting every request value. - Binding pipeline timing: Trace that RoutingMiddleware selects an endpoint and extracts route values as strings, while EndpointMiddleware performs model binding before the filter pipeline and endpoint handler execute.
Why it matters: This timing explains why handlers and endpoint filters receive already-created, typed arguments rather than raw route strings. - Minimal API binding sources: Describe the six binding sources available to minimal API handler parameters: route values, query-string values, header values, a JSON request body, dependency-injected services, and custom binding; distinguish JSON body binding from automatic form binding.
Why it matters: Choosing the correct source determines where an endpoint gets each argument and avoids assuming that form posts are automatically bound.
Key terms: model binding, model binder, endpoint handler, binding, RoutingMiddleware, EndpointMiddleware, route parameters, filter pipeline, route values, query string values
7.2 Binding simple types to a request
This section explains how minimal API handlers bind simple values from routes, query strings, and headers, including custom types that can be parsed with TryParse.
- Convention-based simple binding: Explain how ASP.NET Core chooses between a route value and a query-string value when binding a simple handler parameter. State that a parameter name matching a route-template parameter binds from the route; otherwise ASP.NET Core looks for a query-string value.
Why it matters: These conventions let endpoint handlers receive request values without manually reading the HTTP request. - Explicit simple binding sources: Describe how [FromRoute], [FromQuery], and [FromHeader] force a simple handler parameter to bind from a particular request source. State that these attributes override the default inference, and that headers require [FromHeader] rather than convention-based binding.
Why it matters: Explicit source attributes resolve ambiguity and are the way to receive a simple value from an HTTP header. - Binding failure responses: State what happens when a request value cannot be converted to the target simple type. Explain that minimal API binding throws BadHttpRequestException and produces a 400 Bad Request response for an incompatible format.
Why it matters: Knowing the automatic failure behavior helps you predict how malformed client input is handled. - Custom simple types: Explain how a custom type can participate in simple-type binding by exposing one of the supported TryParse methods. Describe that ASP.NET Core calls TryParse on the incoming route, query-string, or header text; a false result means binding fails and returns 400 Bad Request.
Why it matters: TryParse lets APIs use strongly typed values, such as a ProductId with a required textual format, while retaining normal simple-value binding.
Key terms: model binding, route parameter, route value, query string, handler parameter, [FromRoute], [FromQuery], [FromHeader], binding source, BadHttpRequestException
7.3 Binding complex types to the JSON body
This section explains how minimal API handlers automatically deserialize a JSON request body into one complex parameter, along with the JSON library, limits, and failure behavior involved.
- Complex JSON body binding: Explain how a minimal API binds a JSON request body to a single complex handler parameter. State that ASP.NET Core uses System.Text.Json to deserialize valid JSON into an instance, such as a Product argument, before the handler runs.
Why it matters: This lets endpoint handlers receive structured request data without manual JSON-reading and deserialization code. - JSON serialization configuration: Describe the role of System.Text.Json in minimal APIs for both request-body deserialization and JSON response serialization. State that minimal APIs cannot switch to Newtonsoft.Json, though some System.Text.Json behavior, such as trailing-comma handling and property-name serialization, can be configured.
Why it matters: Knowing the fixed JSON stack and its configurable behavior helps you predict and tailor how an API accepts and produces JSON. - Body-binding restrictions and errors: Distinguish the restrictions on JSON body binding in minimal APIs: only one handler parameter can bind from the body, and a non-JSON body produces a 415 Unsupported Media Type response without running the handler. Describe why binding a body for verbs that do not usually send one, including GET, causes a runtime exception, and how [FromBody] can override that behavior but is discouraged for GET requests.
Why it matters: These rules prevent ambiguous handlers and explain why an endpoint can fail before its handler executes.
Key terms: model binding, complex type, JSON, request body, System.Text.Json, deserialization, serialization, Newtonsoft.Json, trailing commas, property names
7.4 Arrays: Simple types or complex types?
This section explains how minimal APIs bind arrays from repeated query or header values, and when arrays instead bind from a JSON request body.
- Repeated query value arrays: Describe why a repeated query-string key such as ?id=123&id=456 cannot bind to a single int parameter, and how an int[] parameter binds all of those values instead.
Why it matters: Using an array lets an endpoint safely accept multiple values supplied under the same query-string key. - Explicit array parameter names: Explain how an array parameter's name determines the repeated query-string key it binds to, and how [FromQuery(Name = "id")] can let a parameter named ids bind values sent as id.
Why it matters: An explicit binding name keeps handler code readable without forcing API clients to change the request key. - Array binding source rules: Distinguish the conditions under which an array binds from repeated URL values versus the JSON body: only simple-type arrays, string[], or StringValues on body-less verbs such as GET, HEAD, and DELETE get the repeated-value behavior; otherwise ASP.NET Core attempts JSON body binding.
Why it matters: These rules prevent unexpected body-binding failures and help you design endpoints that accept arrays correctly.
Key terms: query string, handler parameter, int[], 400 Bad Request, [FromQuery], [FromRoute], [FromHeader], binding name, simple types, TryParse
7.5 Making parameters optional with nullables
This section explains how minimal API handler parameters are required by default and how nullable parameters or default values allow missing request data.
- Required parameter binding: Explain what happens when a required minimal API handler parameter cannot be bound from its request source. State that this applies to route values, query strings, headers, and request bodies.
Why it matters: Understanding the default required behavior explains why malformed or incomplete requests produce client errors before handler code runs. - Nullable optional parameters: Describe how marking a handler parameter nullable makes it optional and causes a missing bound value to be supplied as null. Distinguish nullable value types such as int? from nullable reference-type annotations for complex JSON-body types.
Why it matters: Optional request data must be represented in the handler signature, or an optional route or absent body can still fail binding. - Null body and NRT behavior: Explain the null behavior for JSON request bodies and why nullable reference types should remain enabled for minimal API endpoints. State that both an absent body and a literal JSON null yield null only for an optional body parameter.
Why it matters: Correct nullability annotations prevent unexpected binding failures and make the endpoint contract clear to both the compiler and callers. - Defaults and optionality diagnostics: Describe the two alternatives for optional handler input: nullable parameters or default parameter values, and explain that built-in analyzers warn when an optional route parameter and handler parameter have mismatched optionality. State that default values require a local function here because lambda parameters cannot have default values in C# 11.
Why it matters: Defaults can provide a useful fallback, while analyzer warnings catch route and handler signatures that would otherwise fail at runtime.
Key terms: EndpointMiddleware, endpoint handler, 400 Bad Request, binding source, nullable, int?, nullable reference types, NRT, JSON body, null
7.6 Binding services and special types
This section introduces special endpoint-handler parameters that ASP.NET Core can bind because it recognizes them, provides them for file uploads, or resolves them as registered application services.
- Special parameter categories: Describe the three categories of special types available as minimal API endpoint-handler parameters: well-known framework types, file-upload types, and application services. Explain that these differ from values created by binding ordinary request data.
Why it matters: These parameter categories let an endpoint access request infrastructure, uploaded files, and application capabilities without manually constructing them. - Well-known framework types: State that well-known types are types ASP.NET Core is hardcoded to understand, and identify HttpContext and HttpRequest as examples introduced in this section.
Why it matters: Well-known types provide direct access to request-related framework objects when an endpoint needs them. - File upload parameter types: Identify IFormFile and IFormFileCollection as special parameter types for working with file uploads.
Why it matters: These types are the endpoint-handler parameters used when an API needs to accept uploaded files. - Registered application services: Describe application services as services registered in WebApplicationBuilder.Services that can be used as endpoint-handler parameters.
Why it matters: Using registered services as parameters gives handlers access to application functionality without creating those services from request data.
Key terms: well-known types, IFormFile, IFormFileCollection, application services, WebApplicationBuilder.Services, endpoint handlers, HttpContext, HttpRequest, ASP.NET Core, file uploads
7.6.1 Injecting well-known types
This section shows how minimal API handlers receive HttpContext and related well-known request types directly as parameters.
- Well-known handler type injection: Explain that a minimal API endpoint handler can receive a well-known type by declaring a parameter of that type. Describe HttpContext as the object containing the low-level details of one request and its response, including services and features.
Why it matters: Declaring the needed parameter lets a handler access request-specific ASP.NET Core information without manually constructing or locating it. - Request type shortcuts: Describe the well-known types that are shortcuts to HttpContext properties: HttpRequest, HttpResponse, CancellationToken, ClaimsPrincipal, Stream, and PipeReader. Distinguish their purposes, including cancellation after a client aborts and efficient processing of large request bodies with Stream or PipeReader.
Why it matters: Choosing the narrow object a handler actually needs makes its purpose clearer and supports efficient request processing.
Key terms: well-known types, endpoint handler, HttpContext, HttpRequest, HttpResponse, CancellationToken, ClaimsPrincipal, Stream, PipeReader
7.6.2 Injecting services
This section explains how minimal API endpoint handlers receive registered dependency-injection services automatically and when explicit [FromServices] binding is useful.
- Automatic service injection: Explain that a registered service can be declared as a parameter of a minimal API endpoint handler and ASP.NET Core injects an instance from the DI container automatically.
Why it matters: Automatic service injection lets endpoint handlers use application and framework capabilities without manually creating those services. - Implicit versus explicit service binding: Distinguish automatic service detection from explicit [FromServices] annotation, and explain why minimal APIs normally favor automatic binding while [FromServices] can be needed with some custom DI containers.
Why it matters: Knowing when explicit binding is unnecessary helps keep endpoint signatures readable while preserving a workaround for uncommon DI-container limitations. - Framework service availability: State that WebApplicationBuilder registers LinkGenerator as a core service, so it is available for injection into endpoint handlers; contrast this with extra features whose services must be added explicitly, such as request logging via AddHttpLogging().
Why it matters: This distinction helps explain why some handler dependencies work immediately while others require application configuration first.
Key terms: registered service, endpoint handler, dependency injection (DI) container, LinkGenerator, [FromServices], custom DI container, minimal APIs, WebApplicationBuilder, AddHttpLogging(), core services
7.6.3 Binding file uploads with IFormFile and IFormFileCollection
This section explains how minimal API handlers accept uploaded files with IFormFile or IFormFileCollection, and why file uploads require strict security and size precautions.
- File upload parameter binding: Describe how a minimal API endpoint accepts one uploaded file with IFormFile or multiple uploaded files with IFormFileCollection, and explain how the handler reads an uploaded file's contents.
Why it matters: These parameter types let an endpoint receive uploaded files while giving the handler access to their metadata and contents. - File upload security precautions: Explain why uploaded files must be treated as potentially malicious, including why an application must not trust the supplied FileName and should generate a new name before saving a file.
Why it matters: Unsafe handling of user-provided filenames or executable uploads can let attackers access or damage files on the server. - Buffered upload size limits: Explain why IFormFile is appropriate for small uploads but unsuitable for large uploads: ASP.NET Core buffers the entire file in memory and on disk before the handler receives it, whereas large uploads may need direct streaming.
Why it matters: Choosing buffered binding for large or uncontrolled uploads can exhaust memory or disk space and cause performance problems.
Key terms: IFormFile, IFormFileCollection, FileName, OpenReadStream, buffered, streaming
7.7 Custom binding with BindAsync
This section shows how minimal API parameter types can implement BindAsync to encapsulate custom request parsing and explains the response behavior when that binding fails.
- BindAsync custom model binding: Explain how implementing a static BindAsync method on an endpoint parameter type enables completely custom model binding in a minimal API. Describe that BindAsync receives HttpContext, can extract needed request data, and can use either the simpler signature or a signature that also receives parameter reflection details.
Why it matters: Custom binding lets you keep unusual request-parsing logic out of endpoint handlers while still accessing the full request. - Binding failure response behavior: Describe the outcome when BindAsync returns null for a required endpoint parameter: EndpointMiddleware throws BadHttpRequestException and produces a 400 response. Distinguish this from throwing an exception inside BindAsync, which EndpointMiddleware does not catch and which results in a 500 response.
Why it matters: Returning null on failed parsing gives invalid client input a 400 response instead of treating it as an unhandled server error. - Custom body format parsing: Describe the SizeDetails example as custom BindAsync parsing of a request body containing two double values separated by a line break, returning a SizeDetails object when parsing succeeds and null when it fails.
Why it matters: The example illustrates when a custom binder is useful: accepting a request format that built-in binding does not handle.
Key terms: model binding, BindAsync, HttpContext, custom model binding, null, EndpointMiddleware, BadHttpRequestException, 400 error, 500 response, required parameter
7.8 Choosing a binding source
This section gives the precedence order minimal APIs use to select a binding source for each handler parameter and explains why binding does not fall back after a failure.
- Binding-source precedence order: Explain the order in which minimal APIs choose a binding source for each handler parameter. Describe that the infrastructure stops at the first applicable source, including the precedence of explicit attributes, well-known types, BindAsync, simple-type route or query binding, simple arrays on bodyless verbs, DI services, and finally JSON-body binding.
Why it matters: Knowing the precedence order lets you diagnose surprising parameter-binding behavior instead of guessing where a value came from. - Binding failure behavior: Describe what happens when the selected binding source fails for a required parameter. State that minimal APIs return a 400 Bad Request and do not continue to a lower-priority binding source, while optional parameters are the exception to the required-parameter condition.
Why it matters: This explains why a request can fail even when the desired value might have been available from another part of the request.
Key terms: binding source, explicit binding source, FromRoute, FromQuery, FromBody, well-known type, binding fails, optional parameter, 400 Bad Request
7.9 Simplifying handlers with AsParameters
This section shows how [AsParameters] groups a minimal API handler’s bound inputs into one type for a clearer signature, then introduces why incoming data must be validated.
- AsParameters handler grouping: Explain how the [AsParameters] attribute wraps multiple endpoint-handler arguments in a single class, record, struct, or record struct to simplify an unwieldy minimal API handler signature.
Why it matters: Grouping request inputs can make an endpoint’s method signature easier to read and maintain. - Binding rules for grouped types: Describe how constructor parameters or properties of an [AsParameters] type follow the same binding attributes and rules as ordinary endpoint-handler parameters, including [From*] attributes, services and well-known types, and body data.
Why it matters: Grouping parameters improves readability without preventing each value from using its appropriate binding source. - Need for input validation: Justify validating data after model binding by explaining that the binder largely assigns request-supplied values blindly, so malformed or malicious input can otherwise reach application code.
Why it matters: Validation protects application logic from bad input such as invalid phone numbers or malicious values.
Key terms: [AsParameters], endpoint handler, record struct, [From*] attributes, constructor parameters, well-known types, model binding, validation, malicious data, SQL injection
7.10 Handling user input with model validation
Introduces the need for validation in minimal APIs and previews DataAnnotations and filter-based parameter validation.
- Validation purpose and necessity: Explain what validation is for in an application and why every app needs to add it when handling user input.
Why it matters: Validation helps an application reject input that does not match the data it expects. - Minimal API validation approach: Describe the validation approach in minimal APIs: validation is not included by default, and the framework supplies nonprescriptive filter hooks so applications can choose how to add it.
Why it matters: Knowing that validation is opt-in prevents you from assuming minimal APIs automatically validate endpoint input. - Validation section roadmap: State that the following material covers the meaning and need for validation, DataAnnotations attributes for describing expected data, and validation of endpoint handler parameters.
Why it matters: This roadmap connects declaring data expectations with enforcing them for minimal API handlers.
Key terms: validation, user input, minimal APIs, filters, nonprescriptive hooks, DataAnnotations, endpoint handler parameters
7.10.1 The need for validation
This section explains why minimal API request data must be validated early and what kinds of malicious and accidental input problems validation addresses.
- Untrusted request input: Explain why values sent in an HTTP request must be treated as untrusted and validated before the endpoint uses them.
Why it matters: Treating request data as untrusted helps prevent harmful or unexpected input from affecting your application. - Early validation timing: Describe when validation should happen in a minimal API: before endpoint handler parameters are used to touch the domain, infrastructure, or information that could be exposed to an attacker, preferably as early as possible in the filter pipeline.
Why it matters: Early validation prevents invalid input from reaching sensitive application code or producing information leaks. - Validation requirement categories: Describe the nonmalicious input requirements validation can enforce: correct formats, permitted numeric ranges, required versus optional values, and business requirements such as converting between different currencies.
Why it matters: Validation improves correctness and user feedback as well as protecting against malicious input. - Minimal API validation support: State that minimal APIs have no built-in feature specifically for these validation requirements, but validation can be implemented with filters and .NET 7 provides attributes that can greatly simplify validation code.
Why it matters: Knowing the available approaches prepares you to choose attributes and filters rather than expecting automatic minimal API validation.
Key terms: validation, endpoint handler parameters, request, user-provided data, minimal API filter pipeline, filters, format, range, required, optional
7.10.2 Using DataAnnotations attributes for validation
This section shows how DataAnnotations and IValidatableObject express validation rules for minimal API binding models, while clarifying their limits and the need to run validation separately.
- DataAnnotations validation metadata: Explain how DataAnnotations attributes decorate a parameter type with metadata that specifies the acceptable state of its bound properties, rather than supplying the property data itself. Describe examples such as requiring a value, limiting a string length, constraining a numeric range, and validating an email-format field.
Why it matters: These attributes make a model’s expected input state explicit and provide the rules that validation code can evaluate. - Attribute choices and limitations: Describe the common DataAnnotations attributes available for isolated property rules, including format, length, range, pattern, required-value, and property-comparison checks. Distinguish format validation for email addresses and phone numbers from verifying that an address or number actually exists.
Why it matters: Choosing an attribute that matches the actual rule prevents a superficial format check from being mistaken for real-world verification. - Cross-property validation rules: Explain that IValidatableObject and its Validate method can add model-level validation when a rule depends on multiple properties, such as requiring an email address or phone number. Describe its limitations: Validate has no easy access to application services and runs only after all DataAnnotations attribute conditions succeed.
Why it matters: Cross-property rules often cannot be expressed by independent property attributes, so they need a model-level or external validation approach. - Validation execution requirement: State that adding DataAnnotations or IValidatableObject rules only declares validation metadata and does not itself validate a minimal API request or return an error. Explain that minimal APIs need code to read the metadata, test the bound model, and return an error response; the next section adds this through a validation filter and a small NuGet package.
Why it matters: Without an executing validation component, invalid input can reach the endpoint handler despite rules declared on the model.
Key terms: DataAnnotations attributes, binding model, [Required], [StringLength], [Range], [EmailAddress], [CreditCard], [MinLength], [Phone], IValidatableObject
7.10.3 Adding a validation filter to your minimal APIs
This section explains how to add DataAnnotations-based validation to minimal API endpoints with a filter, including a workaround for validating simple values.
- Minimal API validation approach: Explain why minimal APIs typically use endpoint filters for validation rather than built-in dedicated validation APIs. State that Microsoft left validation flexible and optional for performance, and that every endpoint must validate incoming data using DataAnnotations or another approach.
Why it matters: Validation prevents untrusted request data from reaching your endpoint logic unchecked. - WithParameterValidation filter behavior: Describe how to install MinimalApis.Extensions and add WithParameterValidation() to an endpoint to validate a complex parameter. Trace that the model is bound from the JSON body first, valid input proceeds to the handler, and invalid input produces a 400 Bad Request Problem Details response describing the errors.
Why it matters: This provides a ready-made way to stop invalid JSON models before endpoint handlers run. - Simple parameter validation workaround: Explain why WithParameterValidation() does not validate a simple int parameter annotated directly in a handler, such as [Range(1, 100)] int id. Describe using an [AsParameters] model with DataAnnotations on its properties as the simplest workaround for validating such simple values.
Why it matters: Wrapping simple inputs in a model lets the validation filter find and enforce their declared rules.
Key terms: minimal APIs, filter pipeline, cross-cutting concern, DataAnnotations, FluentValidation, MinimalApis.Extensions, WithParameterValidation(), 400 Bad Request, Problem Details, [Range]
7.11 Summary
This summary recaps how minimal APIs bind handler parameters from requests, customize binding and signatures, and validate incoming data.
Where this is used later
- Adding metadata to your minimal APIs (chapter 11) · Endpoint metadata and API descriptions need to reflect the request and response shapes produced by JSON serialization.
- Using services from the DI container (chapter 8) · It expands on using services resolved from the DI container.
- Registering custom services with the DI container (chapter 9) · It depends on the idea that custom services must be registered before they can be resolved.
- Authentication in ASP.NET Core: Services and middleware (chapter 23) · Authentication information is available from the request user represented by ClaimsPrincipal.
- Understanding users and claims in ASP.NET Core (chapter 23) · ClaimsPrincipal provides the user authentication information discussed in the authentication chapter.
- Applying authorization policies to minimal API endpoints (chapter 25) · Minimal API authorization depends on authenticated user information associated with requests.
- (chapter intro) (chapter 8) · The earlier use of injected services in minimal API handlers.
- Understanding the benefits of dependency injection (chapter 8) · The earlier use of services injected into minimal API handlers.
Concepts explained in this chapter
- FromBody attributeThe FromBody attribute is an ASP.NET Core parameter-binding attribute that specifies binding a parameter from the deserialized HTTP request body.
- FromQuery attributeThe FromQuery attribute is an ASP.NET Core parameter-binding attribute that specifies binding a parameter from query-string data and can name the query target.
- model bindingA model binder is the framework component that locates request values, converts them to appropriate types, and assigns them to bound objects or parameters.
- dataannotations attributeDataAnnotations is the .NET attribute-based framework for declaring metadata and validation rules on types and their members.
- TryParse methodA TryParse method is a parsing method that converts text to a typed value and reports success through a Boolean return value and an output result.
- FromServices attributeThe FromServices attribute is an ASP.NET Core parameter attribute that directs a handler parameter to be resolved from dependency injection services.
- validationValidation is the application framework process that checks model data against rules to determine whether it is acceptable.
- BadHttpRequestExceptionBadHttpRequestException is an ASP.NET Core exception indicating that an HTTP request is malformed or contains values that cannot be bound or interpreted.
- FromHeader attributeThe FromHeader attribute is an ASP.NET Core parameter-binding attribute that specifies binding a parameter from an HTTP header value.
- IFormFileIFormFile is an ASP.NET Core interface representing a file uploaded through an HTTP form, including its metadata and content access.
- 400 bad requestA 400 status code is an HTTP response status indicating that the server could not process the request because of invalid client input.
- FromRoute attributeThe FromRoute attribute is an ASP.NET Core parameter-binding attribute that specifies binding a parameter from route values.
- BindAsyncBindAsync is a static method convention that allows an ASP.NET Core minimal API parameter type to define custom model-binding logic.
- IFormFileCollectionIFormFileCollection is the ASP.NET Core collection type representing uploaded files received from a multipart form request.
- custom bindingCustom binding is a model-binding technique in which application-defined methods control how a type is created from an HTTP request.
- MinimalApis.ExtensionsMinimalApis.Extensions is a .NET library that adds extensions for ASP.NET Core minimal APIs, including parameter validation support.
- WithParameterValidationWithParameterValidation is a MinimalApis.Extensions endpoint extension method that adds parameter validation to a minimal API endpoint.
- strongly-typed idA strongly typed ID is a domain-specific identifier type that restricts an identifier's representation and conversion to that type.
- AsParametersAttributeAsParametersAttribute is an ASP.NET Core attribute that expands a parameter object's properties or constructor parameters into endpoint parameters bound from multiple request sources.
- binding sourceA binding source is a category of request or application data from which a handler parameter or object property can be populated.
- razor pages filter pipelineAn MVC filter pipeline is the ordered sequence of filters that surrounds and participates in request processing within the ASP.NET Core MVC and Razor Pages frameworks.
- servlet filterIActionFilter is an ASP.NET Core interface for synchronous MVC filters that run before and after action-method execution.
- streamingFile streaming is the technique of processing file content incrementally as it is transferred instead of storing the entire file before processing.
- IValidatableObjectIValidatableObject is a .NET interface that lets an object perform validation involving its own property values and return validation results.
- request messagePOST is an HTTP method used to send data to a server for processing or resource creation.
- nullable reference typesNullable reference types are a C# compiler feature that represents and checks whether reference-type values may be null.
- optional function argumentAn optional parameter is a handler or method parameter that may receive no corresponding input and instead accept a null or default value.
- file uploadA file upload is the transfer of a file from an HTTP client to an application through a request.
- System.Text.JsonSystem.Text.Json is the .NET library for reading and writing JSON data.
- payloadA JWT payload is the token section that contains its claims and other encoded data.
- ClaimsPrincipalClaimsPrincipal is a .NET security object that represents an authenticated user through a collection of claims and identities.
- HTTP responseHttpResponse is the ASP.NET Core object representing the HTTP response sent to a client, including its status code, headers, content type, and body.
- HttpContextHttpContext is the ASP.NET Core object that represents the information and state associated with a single HTTP request and its response.
- plain old CLR objectA plain old CLR object is an ordinary .NET object that does not depend on a specialized framework base type or programming model.
- dependency injection containerThe built-in dependency injection container is the default service container provided by ASP.NET Core for registering and resolving application services.
- serviceA service is a class that provides a discrete piece of functionality to an application and can be registered with its dependency-injection container.
- validation attributeA custom validation attribute is an application-defined attribute that implements a specialized validation rule, typically by deriving from ValidationAttribute.
- default valueA default parameter value is a value specified in a method signature that is supplied when an argument is omitted.
- service registrationService registration is the configuration that maps a requested service or interface to the implementation the dependency-injection container should provide.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
