Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Reflection;

namespace CustomBindingExample;

public class CustomBoundParameter : IBindableFromHttpContext<CustomBoundParameter>
{
public string Value { get; init; } = default!;

public static ValueTask<CustomBoundParameter?> 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<CustomBoundParameter?>(new CustomBoundParameter
{
Value = value
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

// <snippet_IBindableFromHttpContext>
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}";
});
// </snippet_IBindableFromHttpContext>
// <snippet_validation>
app.MapGet("/validated", (ValidatedParameter param) =>
{
if (string.IsNullOrEmpty(param.Value))
{
return Results.BadRequest("Value cannot be empty");
}

return Results.Ok($"Validated value: {param.Value}");
});
// </snippet_validation>

app.Run();
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Reflection;

namespace CustomBindingExample;

public class ValidatedParameter : IBindableFromHttpContext<ValidatedParameter>
{
public string Value { get; init; } = default!;

public static ValueTask<ValidatedParameter?> 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<ValidatedParameter?>(new ValidatedParameter
{
Value = string.Empty
});
}

return ValueTask.FromResult<ValidatedParameter?>(new ValidatedParameter
{
Value = value
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Reflection;

namespace CustomBindingExample;

public class CustomBoundParameter : IBindableFromHttpContext<CustomBoundParameter>
{
public string Value { get; init; } = default!;

public static ValueTask<CustomBoundParameter?> 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<CustomBoundParameter?>(new CustomBoundParameter
{
Value = value
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

// <snippet_IBindableFromHttpContext>
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}";
});
// </snippet_IBindableFromHttpContext>
// <snippet_validation>
app.MapGet("/validated", (ValidatedParameter param) =>
{
if (string.IsNullOrEmpty(param.Value))
{
return Results.BadRequest("Value cannot be empty");
}

return Results.Ok($"Validated value: {param.Value}");
});
// </snippet_validation>

app.Run();
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Reflection;

namespace CustomBindingExample;

public class ValidatedParameter : IBindableFromHttpContext<ValidatedParameter>
{
public string Value { get; init; } = default!;

public static ValueTask<ValidatedParameter?> 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<ValidatedParameter?>(new ValidatedParameter
{
Value = string.Empty
});
}

return ValueTask.FromResult<ValidatedParameter?>(new ValidatedParameter
{
Value = value
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Reflection;

namespace CustomBindingExample;

public class CustomBoundParameter : IBindableFromHttpContext<CustomBoundParameter>
{
public string Value { get; init; } = default!;

public static ValueTask<CustomBoundParameter?> 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<CustomBoundParameter?>(new CustomBoundParameter
{
Value = value
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

// <snippet_IBindableFromHttpContext>
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}";
});
// </snippet_IBindableFromHttpContext>
// <snippet_validation>
app.MapGet("/validated", (ValidatedParameter param) =>
{
if (string.IsNullOrEmpty(param.Value))
{
return Results.BadRequest("Value cannot be empty");
}

return Results.Ok($"Validated value: {param.Value}");
});
// </snippet_validation>

app.Run();
Original file line number Diff line number Diff line change
@@ -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
Loading