diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataApiVersioningOptions.cs b/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataApiVersioningOptions.cs index 575a0a3a..567b0c2e 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataApiVersioningOptions.cs +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataApiVersioningOptions.cs @@ -52,7 +52,7 @@ public ODataApiVersioningOptions( VersionedODataModelBuilder modelBuilder ) => /// /// The associated OData prefix. /// The original options. - public virtual ODataApiVersioningOptions AddRouteComponents( string prefix ) => + public virtual ODataApiVersioningOptions AddRouteComponents( [StringSyntax( "Route" )] string prefix ) => AddRouteComponents( prefix, static _ => { } ); /// @@ -70,7 +70,7 @@ public virtual ODataApiVersioningOptions AddRouteComponents( ActionThe $batch handler. /// The original options. [CLSCompliant( false )] - public ODataApiVersioningOptions AddRouteComponents( string prefix, ODataBatchHandler batchHandler ) => + public ODataApiVersioningOptions AddRouteComponents( [StringSyntax( "Route" )] string prefix, ODataBatchHandler batchHandler ) => AddRouteComponents( prefix, builder => builder.AddSingleton( batchHandler ) ); /// @@ -89,7 +89,7 @@ public ODataApiVersioningOptions AddRouteComponents( ODataBatchHandler batchHand /// The configuration action. /// The original options. public virtual ODataApiVersioningOptions AddRouteComponents( - string prefix, + [StringSyntax( "Route" )] string prefix, Action configureAction ) { configurations ??= new( StringComparer.OrdinalIgnoreCase ); diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiVersionParameterDescriptionContext.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiVersionParameterDescriptionContext.cs index da70b954..8ebe5895 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiVersionParameterDescriptionContext.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiVersionParameterDescriptionContext.cs @@ -117,6 +117,11 @@ public virtual void AddParameter( string name, ApiVersionParameterLocation locat { if ( IsApiVersionNeutral && !Options.AddApiVersionParametersWhenVersionNeutral ) { + if ( location == Path ) + { + UpdateUrlSegment(); + } + return; } diff --git a/src/AspNetCore/WebApi/test/Asp.Versioning.Mvc.ApiExplorer.Tests/ApiVersionParameterDescriptionContextTest.cs b/src/AspNetCore/WebApi/test/Asp.Versioning.Mvc.ApiExplorer.Tests/ApiVersionParameterDescriptionContextTest.cs index ec26b099..8d2e90c7 100644 --- a/src/AspNetCore/WebApi/test/Asp.Versioning.Mvc.ApiExplorer.Tests/ApiVersionParameterDescriptionContextTest.cs +++ b/src/AspNetCore/WebApi/test/Asp.Versioning.Mvc.ApiExplorer.Tests/ApiVersionParameterDescriptionContextTest.cs @@ -82,7 +82,7 @@ public void add_parameter_should_add_descriptor_for_path() Name = "api-version", RouteInfo = new() { - Constraints = new[] { new ApiVersionRouteConstraint() }, + Constraints = [new ApiVersionRouteConstraint()], }, Source = BindingSource.Path, }; @@ -119,6 +119,55 @@ public void add_parameter_should_add_descriptor_for_path() o => o.ExcludingMissingMembers() ); } + [Fact] + public void add_parameter_should_add_descriptor_for_path_when_version_neutral() + { + // arrange + var version = new ApiVersion( 1, 0 ); + var description = new ApiDescription() + { + ActionDescriptor = new ActionDescriptor() { EndpointMetadata = [ApiVersionMetadata.Neutral] }, + ParameterDescriptions = + { + new() + { + Name = "api-version", + RouteInfo = new() { Constraints = [new ApiVersionRouteConstraint()] }, + Source = BindingSource.Path, + }, + }, + }; + var modelMetadata = new Mock( ModelMetadataIdentity.ForType( typeof( string ) ) ).Object; + var options = new ApiExplorerOptions() + { + DefaultApiVersion = version, + ApiVersionParameterSource = new UrlSegmentApiVersionReader(), + }; + var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata, options ); + + // act + context.AddParameter( "api-version", Path ); + + // assert + description.ParameterDescriptions.Single().Should().BeEquivalentTo( + new + { + Name = "api-version", + ModelMetadata = modelMetadata, + Source = BindingSource.Path, + DefaultValue = (object) "1.0", + IsRequired = true, + RouteInfo = new ApiParameterRouteInfo() + { + DefaultValue = "1.0", + IsOptional = false, + Constraints = description.ParameterDescriptions[0].RouteInfo.Constraints, + }, + Type = typeof( string ), + }, + o => o.ExcludingMissingMembers() ); + } + [Fact] public void add_parameter_should_remove_other_descriptors_after_path_parameter_is_added() { @@ -128,7 +177,7 @@ public void add_parameter_should_remove_other_descriptors_after_path_parameter_i Name = "api-version", RouteInfo = new() { - Constraints = new[] { new ApiVersionRouteConstraint() }, + Constraints = [new ApiVersionRouteConstraint()], }, Source = BindingSource.Path, }; @@ -179,7 +228,7 @@ public void add_parameter_should_not_add_query_parameter_after_path_parameter_ha Name = "api-version", RouteInfo = new() { - Constraints = new[] { new ApiVersionRouteConstraint() }, + Constraints = [new ApiVersionRouteConstraint()], }, Source = BindingSource.Path, }; @@ -214,7 +263,7 @@ public void add_parameter_should_add_descriptor_for_media_type_parameter() var metadata = new ApiVersionMetadata( ApiVersionModel.Empty, new ApiVersionModel( version ) ); var description = new ApiDescription() { - ActionDescriptor = new() { EndpointMetadata = new[] { metadata } }, + ActionDescriptor = new() { EndpointMetadata = [metadata] }, SupportedRequestFormats = { new() { MediaType = Json } }, SupportedResponseTypes = { new() { ApiResponseFormats = { new() { MediaType = Json } } } }, }; @@ -304,7 +353,7 @@ public void add_parameter_should_make_parameters_optional_after_first_parameter( private static ApiDescription NewApiDescription( ApiVersion apiVersion, params ApiParameterDescription[] parameters ) { var metadata = new ApiVersionMetadata( ApiVersionModel.Empty, new ApiVersionModel( apiVersion ) ); - var action = new ActionDescriptor() { EndpointMetadata = new[] { metadata } }; + var action = new ActionDescriptor() { EndpointMetadata = [metadata] }; var description = new ApiDescription() { ActionDescriptor = action }; for ( var i = 0; i < parameters.Length; i++ )