Skip to content

Introduce IParameterBindingMetadata to remove unbounded reflection in EndpointMetadataApiDescriptionProvider  #56587

@captainsafia

Description

@captainsafia

Background and Motivation

The EndpointMetadataApiDescriptionProvider is a an implementation of IApiDescriptionProvider that is used to generate ApiDescription instances for minimal APIs that can be used by consumers of ApiExplorer (like Microsoft.AspNetCore.OpenApi) when generating descriptions of the API implementation.

EndpointMetadataApiDescriptionProvider currently relies on unbounded reflection in all scenarios (whether using minimal APIs with static code gen via RequestDelegateGenerator or dynamic code gen via RequestDelegateFactory) to resolve the following information:

  • Whether or not a given parameter has a TryParse method or implements IParsable
  • Whether or not a given parameter is an implementation of type that exposes BindAsync
  • The exploded set of parameters that have been aggregated with the [AsParameters] attribute

It resolves this information using the existing APIs exposed in the ParameterBindingCache. The use of unbounded reflection in this class prevents us from making the entire OpenAPI pipeline trim friendly. To resolve this issue, we will introduce a new metadata type (IParameterBindingMetadata) that will be inserted into endpoints by either RDG or RDF when the endpoints are compiled and used.

Proposed API

// Assembly: Microsoft.AspNetCore.Http.Abstractions

namespace Microsoft.AspNetCore.Http.Metadata;

+ public interface IParameterBindingMetadata
+ {
+	string ParameterName { get; }
+	bool IsTryParsable { get; }
+	bool IsBindAsync { get; }
+	IEnumerable<(ParameterInfo, bool)>? AsParameters { get; }
+ }

public interface IProducesResponseTypeMetadata
{
+	bool IsInferredAwaitable { get; set; }
}

Usage Examples

var parameterBindingMetadata = routeEndpoint.Metadata
	.GetOrderedMetadata<IParameterBindingMetadata>()
	.SingleOrDefault(m => m.ParameterName == parameter.Name);
if (parameterBindingMetadata?.HasTryParse == true)
{
	return BindingSource.Query;
}

Alternative Designs

  • Instead of exposing a single IParameterBindingMetadata instance for each parameter, we could instead expose a single metadata item that allows lookup into a collection of instances using the parameter name as a key.

Risks

  • The shape of this API strongly conforms to the scenarios where we currently use the ParameterBindingCache for method resolution. If the parameter binding implementation for minimal APIs changes in the future, the shape of this API will have to be modified.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesfeature-openapi

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions