BindAsync Surrogate Method in Minimal APIs #50672
Labels
api-suggestion
Early API idea and discussion, it is NOT ready for implementation
area-minimal
Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc
Background and Motivation
Minimal APIs currently support a number of mechanisms for parameter binding, but are limited to a static
TryParse
orBindAsync
method for custom binding.Some types of parameter binding, such as features, cannot be achieved without resorting to
IHttpContextAccessor
. This is both clunky and a forceful hand by platform extenders for consuming developers.TryParse
is insufficient because the process can be more involved than simple parsing andBindAsync
is impractical for types that do not have affinity to HTTP and cannot implementIBindableFromHttpContext<TSelf>
.Consider the following scenario for a Minimal API in ASP.NET API Versioning:
For the
ApiVersion
parameter to be bound (currently), the following DI workaround is required:While this is just one scenario, there are many others like it. This is particularly true for edge cases that continue to crop up in the ever expanding items outlined in the internal EndpointParameterSource enumeration.
Proposed API
The proposed API would expand upon the capabilities of the
BindAsync
conventions and rules by allowing a surrogate method. These surrogates would be defined and consumed through Options. A surrogateBindAsync
method would have the following rules:static
method (to avoid closure issues)BindAsync
conventionIBindableFromHttpContext<TSelf>.BindAsync
signatureBindAsync
implementationThe options might be defined as follows:
To leverage the configuration, the internal
ParameterBindingMethodCache
would have to be changed. This class is source-shared across multiple libraries so the change should only use types known to all implementations (which may otherwise look strange).HasBindAsyncMethod
needs a new overload that can resolve the surrogate mapping dictionary:A new
GetIBindableSurrogate
method would be added to allow resolvingBindAsync
mapped to a specific type.The
FindBindAsyncMethod
aspnetcore/src/Shared/ParameterBindingMethodCache.cs
Line 215 in 28b2bfd
would be updated to allow:
The remaining rules and processing for
BindAsync
would remain unchanged and just work.RequestDelegateFactory
would subsequently be updated as follows:and then:
aspnetcore/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
Line 831 in 28b2bfd
becomes:
and:
aspnetcore/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
Line 1916 in 28b2bfd
becomes:
Usage Examples
This will now allow developers and platform extenders to define arbitrary
BindAsync
methods mapped to a specific type.In the original example, instead of using
IHttpContextAccessor
, API Versioning could now register:This approach would work for any other feature, type, and so on that doesn't have
TryParse
(or is unsuitable) and cannot implementIBindableFromHttpContext<TSelf>
. Consumers of such mappings are none the wiser and do not implicitly have to take a dependency onIHttpContextAccessor
(which should be avoided).Alternative Designs
BindAsyncOptions
does not have to beIReadOnlyDictionary<Type, MethodInfo>
; however,BindAsyncOptions
does not have to supersede existing implementationsstatic
, which means it must be a static function or local functionstatic
lambdas are not guaranteed to be static functions by the compilerstatic (context) => ValueTask.FromResult(context.ApiVersioningFeature().RequestedApiVersion)
Open Questions
BindAsyncOptions.Add
replace an existing registration or are multiple registrations an error?IServiceProvider
is resolved fromRequestDelegateFactoryOptions
Assuming it ties to the root container, resolving the options just works and the following unit test passes:
Risks
BindAsync
implementations might collide (but there can still only be one)BindAsync
processing might be unclearThe text was updated successfully, but these errors were encountered: