dotnet / dotnet/aspnetcore

Extend the ability to customize parameter binding for Minimal APIs

Open
#35,489 35 comments 51 reactions 1 assignee Assigned to @DamianEdwards View on GitHub
api-suggestion area-minimal enhancement feature-minimal-actions Needs: Design triage-focus
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 5h
Merged PRs (30d)
276

Description

This issue is to discuss future updates to extend the ability to customize parameter binding for Minimal APIs, beyond what's available in .NET 6, i.e. static methods `bool TryParse(string input, out T value)` and `ValueTask BindAsync(HttpContext httpContext)` on the target type.

These are some features of parameter binding to consider:

- [ ] bind via target type (sync from request non-body sources, this is `TryParse` in .NET 6)
- [ ] bind via target type (async from request inc. body, this is `BindAsync` in .NET 6)
- [ ] bind via registered type (inc. overwriting built-in binders), e.g. register `IParameterBinder` in DI
- [ ] bind per parameter, e.g. `([Binder(typeof(CustomerBinder))]Customer customer) => { }`
- [ ] register via DI and accept services from DI
- [ ] have access to method/parameter info (i.e. callsite details, access to the parameter is supported by `BindAsync` in .NET 6 now)
- [ ] compose with other binders (e.g. composite binders)
- [ ] emit/mutate endpoint metadata, e.g. for OpenAPI
- [ ] AOT friendliness

### Strawman
``` csharp
public interface IParameterBinderFactory
{
IParameterBinder Create(IServiceProvider provider, ParameterInfo parameter, MethodInfo method);
}

public interface IParameterBinder
{
ValueTask BindAsync(HttpContext httpContext);
}
```

Example usage:

``` csharp
var builder = WebApplication.CreateBuilder();

builder.Services.AddSingleton, CustomerBinder>();

var app = builder.Build();

app.MapPost("/customers", (Cusomter customer) =>
{
return Results.Created(customer);
});

public class CustomerBinder : IParameterBinderFactory, IParameterBinder
{
public CustomerBinder Create(IServiceProvider provider, ParameterInfo parameter, MethodInfo method)
{
// Called at application startup, access to parameter and method here to change behavior based on
// naming, attributes, etc.
return new CustomerBinder();
}

public async ValueTask BindAsync(HttpContext httpContext)
{
// Called per invocation of routing delegate, i.e. per request
// Do whatever custom binding logic desired, including reading from request body, etc.
return await httpContext.Request.ReadAsJsonAsync();
}
}
```

Related issues:
- https://github.com/dotnet/aspnetcore/issues/33955
- https://github.com/dotnet/aspnetcore/issues/35472
- https://github.com/dotnet/aspnetcore/issues/35304

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.