diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/ODataApiDescriptionProvider.cs b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/ODataApiDescriptionProvider.cs index 5736e8f4..fdb4ff8d 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/ODataApiDescriptionProvider.cs +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/ODataApiDescriptionProvider.cs @@ -142,6 +142,7 @@ public virtual void OnProvidersExecuted( ApiDescriptionProviderContext context ) else { UpdateModelTypes( result, matched ); + UpdateFunctionCollectionParameters( result, matched ); } } @@ -456,6 +457,75 @@ private void UpdateModelTypes( ApiDescription description, IODataRoutingMetadata } } + private static void UpdateFunctionCollectionParameters( ApiDescription description, IODataRoutingMetadata metadata ) + { + var parameters = description.ParameterDescriptions; + + if ( parameters.Count == 0 ) + { + return; + } + + var function = default( IEdmFunction ); + var mapping = default( IDictionary ); + + for ( var i = 0; i < metadata.Template.Count; i++ ) + { + var segment = metadata.Template[i]; + + if ( segment is FunctionSegmentTemplate func ) + { + function = func.Function; + mapping = func.ParameterMappings; + break; + } + else if ( segment is FunctionImportSegmentTemplate import ) + { + function = import.FunctionImport.Function; + mapping = import.ParameterMappings; + break; + } + } + + if ( function is null || mapping is null ) + { + return; + } + + var name = default( string ); + + foreach ( var parameter in function.Parameters ) + { + if ( parameter.Type.IsCollection() && + mapping.TryGetValue( parameter.Name, out name ) && + parameters.SingleOrDefault( p => p.Name == name ) is { } param ) + { + param.Source = BindingSource.Path; + break; + } + } + + var path = description.RelativePath; + + if ( string.IsNullOrEmpty( name ) || string.IsNullOrEmpty( path ) ) + { + return; + } + + var span = name.AsSpan(); + Span oldValue = stackalloc char[name.Length + 2]; + Span newValue = stackalloc char[name.Length + 4]; + + newValue[1] = oldValue[0] = '{'; + newValue[^2] = oldValue[^1] = '}'; + newValue[0] = '['; + newValue[^1] = ']'; + span.CopyTo( oldValue.Slice( 1, name.Length ) ); + span.CopyTo( newValue.Slice( 2, name.Length ) ); + + description.RelativePath = path.Replace( oldValue.ToString(), newValue.ToString(), Ordinal ); + } + private sealed class ApiDescriptionComparer : IEqualityComparer { private readonly IEqualityComparer comparer = StringComparer.OrdinalIgnoreCase;