diff --git a/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/CustomBindingExample.csproj b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/CustomBindingExample.csproj
new file mode 100644
index 000000000000..a3a34b647cd2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/CustomBindingExample.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
diff --git a/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/CustomBoundParameters.cs b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/CustomBoundParameters.cs
new file mode 100644
index 000000000000..dd7196638ad2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/CustomBoundParameters.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class CustomBoundParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Custom binding logic here
+ // This example reads from a custom header
+ var value = context.Request.Headers["X-Custom-Header"].ToString();
+
+ // If no header was provided, you could fall back to a query parameter
+ if (string.IsNullOrEmpty(value))
+ {
+ value = context.Request.Query["customValue"].ToString();
+ }
+
+ return ValueTask.FromResult(new CustomBoundParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/Program.cs b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/Program.cs
new file mode 100644
index 000000000000..e77a28063f0c
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/Program.cs
@@ -0,0 +1,34 @@
+
+//
+using CustomBindingExample;
+
+var builder = WebApplication.CreateBuilder(args);
+var app = builder.Build();
+
+app.UseHttpsRedirection();
+
+app.MapGet("/", () => "Hello, IBindableFromHttpContext example!");
+
+app.MapGet("/custom-binding", (CustomBoundParameter param) =>
+{
+ return $"Value from custom binding: {param.Value}";
+});
+
+app.MapGet("/combined/{id}", (int id, CustomBoundParameter param) =>
+{
+ return $"ID: {id}, Custom Value: {param.Value}";
+});
+//
+//
+app.MapGet("/validated", (ValidatedParameter param) =>
+{
+ if (string.IsNullOrEmpty(param.Value))
+ {
+ return Results.BadRequest("Value cannot be empty");
+ }
+
+ return Results.Ok($"Validated value: {param.Value}");
+});
+//
+
+app.Run();
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/TestCustomBindingExample.http b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/TestCustomBindingExample.http
new file mode 100644
index 000000000000..ee106316a2a2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/TestCustomBindingExample.http
@@ -0,0 +1,24 @@
+@host = https://localhost:7176
+
+### Test the root endpoint
+GET {{host}}/
+Accept: text/plain
+
+### Test the custom binding endpoint
+GET {{host}}/custom-binding
+X-Custom-Header: TestHeaderValue
+Accept: text/plain
+
+### Test the combined parameter endpoint
+GET {{host}}/combined/42
+X-Custom-Header: TestHeaderValue
+Accept: text/plain
+
+### Test the validated parameter endpoint - valid case
+GET {{host}}/validated
+X-Custom-Header: ValidValue
+Accept: text/plain
+
+### Test the validated parameter endpoint - invalid case
+GET {{host}}/validated
+Accept: text/plain
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/ValidatedParameters.cs b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/ValidatedParameters.cs
new file mode 100644
index 000000000000..4a048b9c0a46
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/ValidatedParameters.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class ValidatedParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Get the value from a query parameter
+ var value = context.Request.Query["value"].ToString();
+
+ // Perform some basic validation here
+ if (string.IsNullOrEmpty(value))
+ {
+ // Return an empty instance - the controller action will handle the validation failure
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = string.Empty
+ });
+ }
+
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/appsettings.Development.json b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/appsettings.Development.json
new file mode 100644
index 000000000000..0c208ae9181e
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/appsettings.json b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/appsettings.json
new file mode 100644
index 000000000000..ec04bc120fb7
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/CustomBindingExample.cs b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/CustomBindingExample.cs
new file mode 100644
index 000000000000..e580f24c65d6
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/CustomBindingExample.cs
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/CustomBoundParameters.cs b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/CustomBoundParameters.cs
new file mode 100644
index 000000000000..dd7196638ad2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/CustomBoundParameters.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class CustomBoundParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Custom binding logic here
+ // This example reads from a custom header
+ var value = context.Request.Headers["X-Custom-Header"].ToString();
+
+ // If no header was provided, you could fall back to a query parameter
+ if (string.IsNullOrEmpty(value))
+ {
+ value = context.Request.Query["customValue"].ToString();
+ }
+
+ return ValueTask.FromResult(new CustomBoundParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/Program.cs b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/Program.cs
new file mode 100644
index 000000000000..e77a28063f0c
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/Program.cs
@@ -0,0 +1,34 @@
+
+//
+using CustomBindingExample;
+
+var builder = WebApplication.CreateBuilder(args);
+var app = builder.Build();
+
+app.UseHttpsRedirection();
+
+app.MapGet("/", () => "Hello, IBindableFromHttpContext example!");
+
+app.MapGet("/custom-binding", (CustomBoundParameter param) =>
+{
+ return $"Value from custom binding: {param.Value}";
+});
+
+app.MapGet("/combined/{id}", (int id, CustomBoundParameter param) =>
+{
+ return $"ID: {id}, Custom Value: {param.Value}";
+});
+//
+//
+app.MapGet("/validated", (ValidatedParameter param) =>
+{
+ if (string.IsNullOrEmpty(param.Value))
+ {
+ return Results.BadRequest("Value cannot be empty");
+ }
+
+ return Results.Ok($"Validated value: {param.Value}");
+});
+//
+
+app.Run();
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/TestCustomBindingExample.http b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/TestCustomBindingExample.http
new file mode 100644
index 000000000000..254405aed7da
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/TestCustomBindingExample.http
@@ -0,0 +1,18 @@
+@HostAddress = https://localhost:7042
+
+### Basic endpoint with IBindableFromHttpContext
+GET {{HostAddress}}/bindable
+X-Custom-Header: TestHeaderValue
+Accept: text/plain
+
+### IBindableFromHttpContext with query parameter
+GET {{HostAddress}}/bindable?customValue=TestQueryValue
+Accept: text/plain
+
+### IBindableFromHttpContext with validation - valid
+GET {{HostAddress}}/validated?value=ValidValue
+Accept: application/json
+
+### IBindableFromHttpContext with validation - invalid
+GET {{HostAddress}}/validated
+Accept: application/json
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/ValidatedParameters.cs b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/ValidatedParameters.cs
new file mode 100644
index 000000000000..4a048b9c0a46
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/ValidatedParameters.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class ValidatedParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Get the value from a query parameter
+ var value = context.Request.Query["value"].ToString();
+
+ // Perform some basic validation here
+ if (string.IsNullOrEmpty(value))
+ {
+ // Return an empty instance - the controller action will handle the validation failure
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = string.Empty
+ });
+ }
+
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/appsettings.json b/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/appsettings.json
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/CustomBindingExample.csproj b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/CustomBindingExample.csproj
new file mode 100644
index 000000000000..1b28a01c81c7
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/CustomBindingExample.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/CustomBoundParameters.cs b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/CustomBoundParameters.cs
new file mode 100644
index 000000000000..dd7196638ad2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/CustomBoundParameters.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class CustomBoundParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Custom binding logic here
+ // This example reads from a custom header
+ var value = context.Request.Headers["X-Custom-Header"].ToString();
+
+ // If no header was provided, you could fall back to a query parameter
+ if (string.IsNullOrEmpty(value))
+ {
+ value = context.Request.Query["customValue"].ToString();
+ }
+
+ return ValueTask.FromResult(new CustomBoundParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/Program.cs b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/Program.cs
new file mode 100644
index 000000000000..e77a28063f0c
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/Program.cs
@@ -0,0 +1,34 @@
+
+//
+using CustomBindingExample;
+
+var builder = WebApplication.CreateBuilder(args);
+var app = builder.Build();
+
+app.UseHttpsRedirection();
+
+app.MapGet("/", () => "Hello, IBindableFromHttpContext example!");
+
+app.MapGet("/custom-binding", (CustomBoundParameter param) =>
+{
+ return $"Value from custom binding: {param.Value}";
+});
+
+app.MapGet("/combined/{id}", (int id, CustomBoundParameter param) =>
+{
+ return $"ID: {id}, Custom Value: {param.Value}";
+});
+//
+//
+app.MapGet("/validated", (ValidatedParameter param) =>
+{
+ if (string.IsNullOrEmpty(param.Value))
+ {
+ return Results.BadRequest("Value cannot be empty");
+ }
+
+ return Results.Ok($"Validated value: {param.Value}");
+});
+//
+
+app.Run();
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/TestCustomBindingExample.http b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/TestCustomBindingExample.http
new file mode 100644
index 000000000000..ee106316a2a2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/TestCustomBindingExample.http
@@ -0,0 +1,24 @@
+@host = https://localhost:7176
+
+### Test the root endpoint
+GET {{host}}/
+Accept: text/plain
+
+### Test the custom binding endpoint
+GET {{host}}/custom-binding
+X-Custom-Header: TestHeaderValue
+Accept: text/plain
+
+### Test the combined parameter endpoint
+GET {{host}}/combined/42
+X-Custom-Header: TestHeaderValue
+Accept: text/plain
+
+### Test the validated parameter endpoint - valid case
+GET {{host}}/validated
+X-Custom-Header: ValidValue
+Accept: text/plain
+
+### Test the validated parameter endpoint - invalid case
+GET {{host}}/validated
+Accept: text/plain
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/ValidatedParameters.cs b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/ValidatedParameters.cs
new file mode 100644
index 000000000000..4a048b9c0a46
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/ValidatedParameters.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class ValidatedParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Get the value from a query parameter
+ var value = context.Request.Query["value"].ToString();
+
+ // Perform some basic validation here
+ if (string.IsNullOrEmpty(value))
+ {
+ // Return an empty instance - the controller action will handle the validation failure
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = string.Empty
+ });
+ }
+
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/appsettings.Development.json b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/appsettings.Development.json
new file mode 100644
index 000000000000..0c208ae9181e
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/appsettings.json b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/appsettings.json
new file mode 100644
index 000000000000..ec04bc120fb7
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/CustomBindingExample.csproj b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/CustomBindingExample.csproj
new file mode 100644
index 000000000000..6568b3dcfb4b
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/CustomBindingExample.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
diff --git a/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/CustomBoundParameters.cs b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/CustomBoundParameters.cs
new file mode 100644
index 000000000000..dd7196638ad2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/CustomBoundParameters.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class CustomBoundParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Custom binding logic here
+ // This example reads from a custom header
+ var value = context.Request.Headers["X-Custom-Header"].ToString();
+
+ // If no header was provided, you could fall back to a query parameter
+ if (string.IsNullOrEmpty(value))
+ {
+ value = context.Request.Query["customValue"].ToString();
+ }
+
+ return ValueTask.FromResult(new CustomBoundParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/Program.cs b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/Program.cs
new file mode 100644
index 000000000000..e77a28063f0c
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/Program.cs
@@ -0,0 +1,34 @@
+
+//
+using CustomBindingExample;
+
+var builder = WebApplication.CreateBuilder(args);
+var app = builder.Build();
+
+app.UseHttpsRedirection();
+
+app.MapGet("/", () => "Hello, IBindableFromHttpContext example!");
+
+app.MapGet("/custom-binding", (CustomBoundParameter param) =>
+{
+ return $"Value from custom binding: {param.Value}";
+});
+
+app.MapGet("/combined/{id}", (int id, CustomBoundParameter param) =>
+{
+ return $"ID: {id}, Custom Value: {param.Value}";
+});
+//
+//
+app.MapGet("/validated", (ValidatedParameter param) =>
+{
+ if (string.IsNullOrEmpty(param.Value))
+ {
+ return Results.BadRequest("Value cannot be empty");
+ }
+
+ return Results.Ok($"Validated value: {param.Value}");
+});
+//
+
+app.Run();
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/TestCustomBindingExample.http b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/TestCustomBindingExample.http
new file mode 100644
index 000000000000..ee106316a2a2
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/TestCustomBindingExample.http
@@ -0,0 +1,24 @@
+@host = https://localhost:7176
+
+### Test the root endpoint
+GET {{host}}/
+Accept: text/plain
+
+### Test the custom binding endpoint
+GET {{host}}/custom-binding
+X-Custom-Header: TestHeaderValue
+Accept: text/plain
+
+### Test the combined parameter endpoint
+GET {{host}}/combined/42
+X-Custom-Header: TestHeaderValue
+Accept: text/plain
+
+### Test the validated parameter endpoint - valid case
+GET {{host}}/validated
+X-Custom-Header: ValidValue
+Accept: text/plain
+
+### Test the validated parameter endpoint - invalid case
+GET {{host}}/validated
+Accept: text/plain
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/ValidatedParameters.cs b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/ValidatedParameters.cs
new file mode 100644
index 000000000000..4a048b9c0a46
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/ValidatedParameters.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+
+namespace CustomBindingExample;
+
+public class ValidatedParameter : IBindableFromHttpContext
+{
+ public string Value { get; init; } = default!;
+
+ public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ {
+ // Get the value from a query parameter
+ var value = context.Request.Query["value"].ToString();
+
+ // Perform some basic validation here
+ if (string.IsNullOrEmpty(value))
+ {
+ // Return an empty instance - the controller action will handle the validation failure
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = string.Empty
+ });
+ }
+
+ return ValueTask.FromResult(new ValidatedParameter
+ {
+ Value = value
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/appsettings.Development.json b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/appsettings.Development.json
new file mode 100644
index 000000000000..0c208ae9181e
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/appsettings.json b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/appsettings.json
new file mode 100644
index 000000000000..ec04bc120fb7
--- /dev/null
+++ b/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
\ No newline at end of file
diff --git a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding10.md b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding10.md
index 57e0fd53a662..1f4ac48e4336 100644
--- a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding10.md
+++ b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding10.md
@@ -321,10 +321,11 @@ The [complete sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tre
### Custom Binding
-There are two ways to customize parameter binding:
+There are three ways to customize parameter binding:
1. For route, query, and header binding sources, bind custom types by adding a static `TryParse` method for the type.
1. Control the binding process by implementing a `BindAsync` method on a type.
+1. For advanced scenarios, implement the interface to provide custom binding logic directly from the `HttpContext`.
#### TryParse
@@ -354,6 +355,32 @@ The following code displays `SortBy:xyz, SortDirection:Desc, CurrentPage:99` wit
+#### Custom parameter binding with `IBindableFromHttpContext`
+
+ASP.NET Core provides support for custom parameter binding in Minimal APIs using the interface. This interface, introduced with C# 11's static abstract members, allows you to create types that can be bound from an HTTP context directly in route handler parameters.
+
+```csharp
+public interface IBindableFromHttpContext
+ where TSelf : class, IBindableFromHttpContext
+{
+ static abstract ValueTask BindAsync(HttpContext context, ParameterInfo parameter);
+}
+```
+
+By implementing the , you can create custom types that handle their own binding logic from the HttpContext. When a route handler includes a parameter of this type, the framework automatically calls the static BindAsync method to create the instance:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/Program.cs" id="snippet_IBindableFromHttpContext":::
+
+The following is an example implementation of a custom parameter that binds from an HTTP header:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/CustomBoundParameters.cs":::
+
+You can also implement validation within your custom binding logic:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/10.0-samples/CustomBindingExample/Program.cs" id="snippet_Validation":::
+
+[View or download the sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/minimal-apis/10.0-samples/CustomBindingExample) ([how to download](xref:index#how-to-download-a-sample))
+
### Binding failures
When binding fails, the framework logs a debug message and returns various status codes to the client depending on the failure mode.
diff --git a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding7.md b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding7.md
index 54b284265abd..d78b27f5c435 100644
--- a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding7.md
+++ b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding7.md
@@ -249,10 +249,11 @@ The [complete sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tre
### Custom Binding
-There are two ways to customize parameter binding:
+There are three ways to customize parameter binding:
1. For route, query, and header binding sources, bind custom types by adding a static `TryParse` method for the type.
1. Control the binding process by implementing a `BindAsync` method on a type.
+1. For advanced scenarios, implement the interface to provide custom binding logic directly from the `HttpContext`.
#### TryParse
@@ -282,6 +283,32 @@ The following code displays `SortBy:xyz, SortDirection:Desc, CurrentPage:99` wit
+#### Custom parameter binding with `IBindableFromHttpContext`
+
+ASP.NET Core provides support for custom parameter binding in Minimal APIs using the interface. This interface, introduced with C# 11's static abstract members, allows you to create types that can be bound from an HTTP context directly in route handler parameters.
+
+```csharp
+public interface IBindableFromHttpContext
+ where TSelf : class, IBindableFromHttpContext
+{
+ static abstract ValueTask BindAsync(HttpContext context, ParameterInfo parameter);
+}
+```
+
+By implementing the , you can create custom types that handle their own binding logic from the HttpContext. When a route handler includes a parameter of this type, the framework automatically calls the static BindAsync method to create the instance:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/Program.cs" id="snippet_IBindableFromHttpContext":::
+
+The following is an example implementation of a custom parameter that binds from an HTTP header:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/CustomBoundParameters.cs":::
+
+You can also implement validation within your custom binding logic:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/7.0-samples/CustomBindingExample/Program.cs" id="snippet_Validation":::
+
+[View or download the sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/minimal-apis/7.0-samples/CustomBindingExample) ([how to download](xref:index#how-to-download-a-sample))
+
### Binding failures
When binding fails, the framework logs a debug message and returns various status codes to the client depending on the failure mode.
diff --git a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding8.md b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding8.md
index 841f36a6c64e..0c3fb760027f 100644
--- a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding8.md
+++ b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding8.md
@@ -321,10 +321,11 @@ The [complete sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tre
### Custom Binding
-There are two ways to customize parameter binding:
+There are three ways to customize parameter binding:
1. For route, query, and header binding sources, bind custom types by adding a static `TryParse` method for the type.
1. Control the binding process by implementing a `BindAsync` method on a type.
+1. For advanced scenarios, implement the interface to provide custom binding logic directly from the `HttpContext`.
#### TryParse
@@ -354,6 +355,32 @@ The following code displays `SortBy:xyz, SortDirection:Desc, CurrentPage:99` wit
+#### Custom parameter binding with `IBindableFromHttpContext`
+
+ASP.NET Core provides support for custom parameter binding in Minimal APIs using the interface. This interface, introduced with C# 11's static abstract members, allows you to create types that can be bound from an HTTP context directly in route handler parameters.
+
+```csharp
+public interface IBindableFromHttpContext
+ where TSelf : class, IBindableFromHttpContext
+{
+ static abstract ValueTask BindAsync(HttpContext context, ParameterInfo parameter);
+}
+```
+
+By implementing the , you can create custom types that handle their own binding logic from the HttpContext. When a route handler includes a parameter of this type, the framework automatically calls the static BindAsync method to create the instance:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/Program.cs" id="snippet_IBindableFromHttpContext":::
+
+The following is an example implementation of a custom parameter that binds from an HTTP header:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/CustomBoundParameters.cs":::
+
+You can also implement validation within your custom binding logic:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/8.0-samples/CustomBindingExample/Program.cs" id="snippet_Validation":::
+
+[View or download the sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/minimal-apis/8.0-samples/CustomBindingExample) ([how to download](xref:index#how-to-download-a-sample))
+
### Binding failures
When binding fails, the framework logs a debug message and returns various status codes to the client depending on the failure mode.
diff --git a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding9.md b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding9.md
index b946ee939e75..55a11acd2633 100644
--- a/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding9.md
+++ b/aspnetcore/fundamentals/minimal-apis/includes/parameter-binding9.md
@@ -321,10 +321,11 @@ The [complete sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tre
### Custom Binding
-There are two ways to customize parameter binding:
+There are three ways to customize parameter binding:
1. For route, query, and header binding sources, bind custom types by adding a static `TryParse` method for the type.
1. Control the binding process by implementing a `BindAsync` method on a type.
+1. For advanced scenarios, implement the interface to provide custom binding logic directly from the `HttpContext`.
#### TryParse
@@ -354,6 +355,32 @@ The following code displays `SortBy:xyz, SortDirection:Desc, CurrentPage:99` wit
+#### Custom parameter binding with `IBindableFromHttpContext`
+
+ASP.NET Core provides support for custom parameter binding in Minimal APIs using the interface. This interface, introduced with C# 11's static abstract members, allows you to create types that can be bound from an HTTP context directly in route handler parameters.
+
+```csharp
+public interface IBindableFromHttpContext
+ where TSelf : class, IBindableFromHttpContext
+{
+ static abstract ValueTask BindAsync(HttpContext context, ParameterInfo parameter);
+}
+```
+
+By implementing the , you can create custom types that handle their own binding logic from the HttpContext. When a route handler includes a parameter of this type, the framework automatically calls the static BindAsync method to create the instance:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/Program.cs" id="snippet_IBindableFromHttpContext":::
+
+The following is an example implementation of a custom parameter that binds from an HTTP header:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/CustomBoundParameters.cs":::
+
+You can also implement validation within your custom binding logic:
+
+:::code language="csharp" source="~/fundamentals/minimal-apis/9.0-samples/CustomBindingExample/Program.cs" id="snippet_Validation":::
+
+[View or download the sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/minimal-apis/9.0-samples/CustomBindingExample) ([how to download](xref:index#how-to-download-a-sample))
+
### Binding failures
When binding fails, the framework logs a debug message and returns various status codes to the client depending on the failure mode.
diff --git a/aspnetcore/fundamentals/minimal-apis/parameter-binding.md b/aspnetcore/fundamentals/minimal-apis/parameter-binding.md
index 7f6ee4a329bc..55a79bd352a8 100644
--- a/aspnetcore/fundamentals/minimal-apis/parameter-binding.md
+++ b/aspnetcore/fundamentals/minimal-apis/parameter-binding.md
@@ -4,8 +4,9 @@ author: wadepickett
description: Learn how parameters are populated before invoking minimal route handlers.
ms.author: wpickett
monikerRange: '>= aspnetcore-7.0'
-ms.date: 07/09/2025
+ms.date: 09/02/2025
uid: fundamentals/minimal-apis/parameter-binding
+ai-usage: ai-assisted
---
# Parameter Binding in Minimal API apps