Skip to content

Commit 41d7c86

Browse files
wadepickettCopilot
andauthored
Minimal API responses.md: add missing IBindableFromHttpContext section (#35999)
* Minimal API responces.md add missing IBindableFromHttpContext secton * Added more code samples and intros * Fixed code link * Update aspnetcore/fundamentals/minimal-apis/includes/responses7-8.md Fixed typo on code link * Moved to parameter-binding * Removed extra line space * Moved new section to after BindAsync and added to intro * Fixed code link * Removed v8-9 app sample and inlcudes since they are dupes * Corrected links to parameter-binding8-10.md * Fixed one more link to parmeter-binding8-10.md * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent c787d87 commit 41d7c86

21 files changed

+317
-870
lines changed

aspnetcore/fundamentals/minimal-apis.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ The <xref:System.Delegate> arguments passed to these methods are called "route h
6868

6969
## Parameter binding
7070

71-
[!INCLUDE [](~/fundamentals/minimal-apis/includes/parameter-binding10.md)]
71+
[!INCLUDE [](~/fundamentals/minimal-apis/includes/parameter-binding8-10.md)]
7272

7373
## Json+PipeReader deserialization in minimal APIs
7474

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Reflection;
2+
3+
namespace CustomBindingExample;
4+
5+
public class CustomBoundParameter : IBindableFromHttpContext<CustomBoundParameter>
6+
{
7+
public string Value { get; init; } = default!;
8+
9+
public static ValueTask<CustomBoundParameter?> BindAsync(HttpContext context, ParameterInfo parameter)
10+
{
11+
// Custom binding logic here
12+
// This example reads from a custom header
13+
var value = context.Request.Headers["X-Custom-Header"].ToString();
14+
15+
// If no header was provided, you could fall back to a query parameter
16+
if (string.IsNullOrEmpty(value))
17+
{
18+
value = context.Request.Query["customValue"].ToString();
19+
}
20+
21+
return ValueTask.FromResult<CustomBoundParameter?>(new CustomBoundParameter
22+
{
23+
Value = value
24+
});
25+
}
26+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
// <snippet_IBindableFromHttpContext>
3+
using CustomBindingExample;
4+
5+
var builder = WebApplication.CreateBuilder(args);
6+
var app = builder.Build();
7+
8+
app.UseHttpsRedirection();
9+
10+
app.MapGet("/", () => "Hello, IBindableFromHttpContext example!");
11+
12+
app.MapGet("/custom-binding", (CustomBoundParameter param) =>
13+
{
14+
return $"Value from custom binding: {param.Value}";
15+
});
16+
17+
app.MapGet("/combined/{id}", (int id, CustomBoundParameter param) =>
18+
{
19+
return $"ID: {id}, Custom Value: {param.Value}";
20+
});
21+
// </snippet_IBindableFromHttpContext>
22+
// <snippet_validation>
23+
app.MapGet("/validated", (ValidatedParameter param) =>
24+
{
25+
if (string.IsNullOrEmpty(param.Value))
26+
{
27+
return Results.BadRequest("Value cannot be empty");
28+
}
29+
30+
return Results.Ok($"Validated value: {param.Value}");
31+
});
32+
// </snippet_validation>
33+
34+
app.Run();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@host = https://localhost:7176
2+
3+
### Test the root endpoint
4+
GET {{host}}/
5+
Accept: text/plain
6+
7+
### Test the custom binding endpoint
8+
GET {{host}}/custom-binding
9+
X-Custom-Header: TestHeaderValue
10+
Accept: text/plain
11+
12+
### Test the combined parameter endpoint
13+
GET {{host}}/combined/42
14+
X-Custom-Header: TestHeaderValue
15+
Accept: text/plain
16+
17+
### Test the validated parameter endpoint - valid case
18+
GET {{host}}/validated?value=ValidValue
19+
Accept: text/plain
20+
21+
### Test the validated parameter endpoint - invalid case
22+
GET {{host}}/validated
23+
Accept: text/plain
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System.Reflection;
2+
3+
namespace CustomBindingExample;
4+
5+
public class ValidatedParameter : IBindableFromHttpContext<ValidatedParameter>
6+
{
7+
public string Value { get; init; } = default!;
8+
9+
public static ValueTask<ValidatedParameter?> BindAsync(HttpContext context, ParameterInfo parameter)
10+
{
11+
// Get the value from a query parameter
12+
var value = context.Request.Query["value"].ToString();
13+
14+
// Perform some basic validation here
15+
if (string.IsNullOrEmpty(value))
16+
{
17+
// Return an empty instance - the route handler will handle the validation failure
18+
return ValueTask.FromResult<ValidatedParameter?>(new ValidatedParameter
19+
{
20+
Value = string.Empty
21+
});
22+
}
23+
24+
return ValueTask.FromResult<ValidatedParameter?>(new ValidatedParameter
25+
{
26+
Value = value
27+
});
28+
}
29+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net7.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Reflection;
2+
3+
namespace CustomBindingExample;
4+
5+
public class CustomBoundParameter : IBindableFromHttpContext<CustomBoundParameter>
6+
{
7+
public string Value { get; init; } = default!;
8+
9+
public static ValueTask<CustomBoundParameter?> BindAsync(HttpContext context, ParameterInfo parameter)
10+
{
11+
// Custom binding logic here
12+
// This example reads from a custom header
13+
var value = context.Request.Headers["X-Custom-Header"].ToString();
14+
15+
// If no header was provided, you could fall back to a query parameter
16+
if (string.IsNullOrEmpty(value))
17+
{
18+
value = context.Request.Query["customValue"].ToString();
19+
}
20+
21+
return ValueTask.FromResult<CustomBoundParameter?>(new CustomBoundParameter
22+
{
23+
Value = value
24+
});
25+
}
26+
}

0 commit comments

Comments
 (0)