Skip to content

Commit d5ceba9

Browse files
Chris Martinezcommonsensesoftware
authored andcommitted
Add option to support qualified names in URL generation and deprecate operation-specific option
1 parent 3f31c81 commit d5ceba9

File tree

10 files changed

+69
-22
lines changed

10 files changed

+69
-22
lines changed

src/Common.OData.ApiExplorer/AspNet.OData/Routing/ODataRouteBuilder.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,7 @@ void AppendEntitySetOrOperation( IList<string> segments )
143143
AppendEntityKeysFromConvention( builder );
144144
segments.Add( builder.ToString() );
145145
builder.Clear();
146-
#if API_EXPLORER
147-
builder.Append( Context.Options.UseQualifiedOperationNames ? Context.Operation.ShortQualifiedName() : Context.Operation.Name );
148-
#else
149-
builder.Append( Context.Operation.ShortQualifiedName() );
150-
#endif
146+
builder.Append( Context.Options.UseQualifiedNames ? Context.Operation.ShortQualifiedName() : Context.Operation.Name );
151147
AppendParametersFromConvention( builder, Context.Operation );
152148
break;
153149
case UnboundOperation:

src/Common.OData.ApiExplorer/AspNet.OData/Routing/ODataRouteBuilderContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.AspNetCore.Mvc.Abstractions;
66
using Microsoft.AspNetCore.Mvc.ApiExplorer;
77
using Microsoft.AspNetCore.Mvc.Controllers;
8+
using Microsoft.AspNetCore.Mvc.Versioning;
89
#endif
910
using Microsoft.Extensions.DependencyInjection;
1011
using Microsoft.OData;
@@ -38,6 +39,8 @@ sealed partial class ODataRouteBuilderContext
3839

3940
internal ODataRouteTemplateGenerationKind RouteTemplateGeneration { get; } = Client;
4041
#else
42+
internal ODataApiVersioningOptions Options { get; }
43+
4144
internal IList<ParameterDescriptor> ParameterDescriptions => ActionDescriptor.Parameters;
4245

4346
internal ODataRouteTemplateGenerationKind RouteTemplateGeneration { get; } = Server;

src/Common.OData.ApiExplorer/ODataApiExplorerOptions.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
77
using Microsoft.AspNet.OData;
88
using Microsoft.AspNet.OData.Builder;
99
using System;
10+
using System.ComponentModel;
1011
#if WEBAPI
1112
using System.Web.Http;
1213
using System.Web.Http.Description;
1314
#else
1415
using Microsoft.AspNetCore.Mvc;
1516
#endif
17+
using static System.ComponentModel.EditorBrowsableState;
1618

1719
/// <summary>
1820
/// Represents the possible API versioning options for an OData API explorer.
@@ -36,7 +38,19 @@ public partial class ODataApiExplorerOptions : ApiExplorerOptions
3638
/// Gets or sets a value indicating whether qualified names are used when building URLs for operations (e.g. actions and functions).
3739
/// </summary>
3840
/// <value>True if qualified names are used when building URLs for operations; otherwise, false. The default value is <c>false</c>.</value>
39-
public bool UseQualifiedOperationNames { get; set; }
41+
[EditorBrowsable( Never )]
42+
[Obsolete( "This property will be removed in the next major version. Use UseQualifiedNames instead.", error: true )]
43+
public bool UseQualifiedOperationNames
44+
{
45+
get => UseQualifiedNames;
46+
set => UseQualifiedNames = value;
47+
}
48+
49+
/// <summary>
50+
/// Gets or sets a value indicating whether qualified names are used when building URLs.
51+
/// </summary>
52+
/// <value>True if qualified names are used when building URLs; otherwise, false. The default value is <c>false</c>.</value>
53+
public bool UseQualifiedNames { get; set; }
4054

4155
/// <summary>
4256
/// Gets or sets the convention builder used to describe OData query options.

src/Microsoft.AspNetCore.Mvc.Versioning/Builder/IApplicationBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public static class IApplicationBuilderExtensions
1717
/// <remarks>
1818
/// <para>
1919
/// Configuration of the API versioning middleware is not necessary unless you explicitly
20-
/// want to control when the middleware is added in the pipline. API versioning automatically configures
20+
/// want to control when the middleware is added in the pipeline. API versioning automatically configures
2121
/// the required middleware, which is usually early enough for dependent middleware.
2222
/// </para>
2323
/// <para>

src/Microsoft.AspNetCore.OData.Versioning.ApiExplorer/AspNetCore.Mvc.ApiExplorer/ODataApiDescriptionProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ static string BuildRelativePath( ControllerActionDescriptor action, ODataRouteBu
365365
var relativePath = action.AttributeRouteInfo?.Template;
366366

367367
// note: if path happens to be built adhead of time, it's expected to be qualified; rebuild it as necessary
368-
if ( string.IsNullOrEmpty( relativePath ) || !routeContext.Options.UseQualifiedOperationNames )
368+
if ( string.IsNullOrEmpty( relativePath ) || !routeContext.Options.UseQualifiedNames )
369369
{
370370
var builder = new ODataRouteBuilder( routeContext );
371371
relativePath = builder.Build();

src/Microsoft.AspNetCore.OData.Versioning.ApiExplorer/Extensions.DependencyInjection/IServiceCollectionExtensions.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace Microsoft.Extensions.DependencyInjection
22
{
33
using Microsoft.AspNetCore.Mvc.ApiExplorer;
4+
using Microsoft.AspNetCore.Mvc.Versioning;
45
using Microsoft.Extensions.DependencyInjection.Extensions;
56
using Microsoft.Extensions.Options;
67
using System;
@@ -50,18 +51,29 @@ static void AddApiExplorerServices( IServiceCollection services )
5051
{
5152
services.AddVersionedApiExplorer();
5253
services.TryAdd( Singleton<IOptionsFactory<ODataApiExplorerOptions>, ApiExplorerOptionsFactory<ODataApiExplorerOptions>>() );
53-
services.Replace( Singleton<IOptionsFactory<ApiExplorerOptions>>( sp => new ODataApiExplorerOptionsAdapter( sp.GetRequiredService<IOptionsFactory<ODataApiExplorerOptions>>() ) ) );
54-
services.Replace( Singleton( typeof( ApiExplorerOptions ), sp => sp.GetRequiredService<ODataApiExplorerOptions>() ) );
54+
services.Replace( Singleton<IOptionsFactory<ApiExplorerOptions>, ODataApiExplorerOptionsAdapter>() );
5555
services.TryAddEnumerable( Transient<IApiDescriptionProvider, ODataApiDescriptionProvider>() );
5656
}
5757

5858
sealed class ODataApiExplorerOptionsAdapter : IOptionsFactory<ApiExplorerOptions>
5959
{
60+
readonly IOptions<ODataApiVersioningOptions> options;
6061
readonly IOptionsFactory<ODataApiExplorerOptions> factory;
6162

62-
internal ODataApiExplorerOptionsAdapter( IOptionsFactory<ODataApiExplorerOptions> factory ) => this.factory = factory;
63+
public ODataApiExplorerOptionsAdapter(
64+
IOptions<ODataApiVersioningOptions> options,
65+
IOptionsFactory<ODataApiExplorerOptions> factory )
66+
{
67+
this.options = options;
68+
this.factory = factory;
69+
}
6370

64-
public ApiExplorerOptions Create( string name ) => factory.Create( name );
71+
public ApiExplorerOptions Create( string name )
72+
{
73+
var newOptions = factory.Create( name );
74+
newOptions.UseQualifiedNames = options.Value.UseQualifiedNames;
75+
return newOptions;
76+
}
6577
}
6678
}
6779
}

src/Microsoft.AspNetCore.OData.Versioning/AspNet.OData/Routing/ODataRouteBindingInfoConvention.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using Microsoft.AspNetCore.Mvc.Controllers;
66
using Microsoft.AspNetCore.Mvc.ModelBinding;
77
using Microsoft.AspNetCore.Mvc.Routing;
8+
using Microsoft.AspNetCore.Mvc.Versioning;
9+
using Microsoft.Extensions.Options;
810
using Microsoft.OData.Edm;
911
using System;
1012
using System.Collections.Generic;
@@ -18,21 +20,28 @@
1820

1921
sealed class ODataRouteBindingInfoConvention : IODataActionDescriptorConvention
2022
{
23+
readonly IOptions<ODataApiVersioningOptions> options;
24+
2125
internal ODataRouteBindingInfoConvention(
2226
IODataRouteCollectionProvider routeCollectionProvider,
23-
IModelMetadataProvider modelMetadataProvider )
27+
IModelMetadataProvider modelMetadataProvider,
28+
IOptions<ODataApiVersioningOptions> options )
2429
{
2530
Contract.Requires( routeCollectionProvider != null );
2631
Contract.Requires( modelMetadataProvider != null );
32+
Contract.Requires( options != null );
2733

2834
RouteCollectionProvider = routeCollectionProvider;
2935
ModelMetadataProvider = modelMetadataProvider;
36+
this.options = options;
3037
}
3138

3239
IODataRouteCollectionProvider RouteCollectionProvider { get; }
3340

3441
IModelMetadataProvider ModelMetadataProvider { get; }
3542

43+
ODataApiVersioningOptions Options => options.Value;
44+
3645
public void Apply( ActionDescriptorProviderContext context, ControllerActionDescriptor action )
3746
{
3847
Contract.Requires( context != null );
@@ -95,7 +104,7 @@ void UpdateBindingInfo( ControllerActionDescriptor action, ODataRouteMapping map
95104
Contract.Requires( mapping != null );
96105
Contract.Requires( routeInfos != null );
97106

98-
var routeContext = new ODataRouteBuilderContext( mapping, action );
107+
var routeContext = new ODataRouteBuilderContext( mapping, action, Options );
99108
var routeBuilder = new ODataRouteBuilder( routeContext );
100109
var parameterContext = new ActionParameterContext( routeBuilder, routeContext );
101110

src/Microsoft.AspNetCore.OData.Versioning/AspNet.OData/Routing/ODataRouteBuilderContext.Core.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
using Microsoft.AspNet.OData;
44
using Microsoft.AspNetCore.Mvc.Controllers;
5+
using Microsoft.AspNetCore.Mvc.Versioning;
56
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.OData;
78
using Microsoft.OData.Edm;
@@ -15,10 +16,14 @@ partial class ODataRouteBuilderContext
1516
{
1617
private IODataPathTemplateHandler templateHandler;
1718

18-
internal ODataRouteBuilderContext( ODataRouteMapping routeMapping, ControllerActionDescriptor actionDescriptor )
19+
internal ODataRouteBuilderContext(
20+
ODataRouteMapping routeMapping,
21+
ControllerActionDescriptor actionDescriptor,
22+
ODataApiVersioningOptions options )
1923
{
2024
Contract.Requires( routeMapping != null );
2125
Contract.Requires( actionDescriptor != null );
26+
Contract.Requires( options != null );
2227

2328
ApiVersion = routeMapping.ApiVersion;
2429
serviceProvider = routeMapping.Services;
@@ -27,6 +32,7 @@ internal ODataRouteBuilderContext( ODataRouteMapping routeMapping, ControllerAct
2732
RouteTemplate = routeAttribute?.PathTemplate;
2833
Route = routeMapping.Route;
2934
ActionDescriptor = actionDescriptor;
35+
Options = options;
3036
UrlKeyDelimiter = serviceProvider.GetRequiredService<ODataOptions>().UrlKeyDelimiter ?? Parentheses;
3137

3238
var container = EdmModel.EntityContainer;

src/Microsoft.AspNetCore.OData.Versioning/AspNetCore.Mvc/ODataActionDescriptorProvider.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,32 @@
33
using Microsoft.AspNet.OData;
44
using Microsoft.AspNet.OData.Routing;
55
using Microsoft.AspNetCore.Mvc.Abstractions;
6-
using Microsoft.AspNetCore.Mvc.ApplicationParts;
76
using Microsoft.AspNetCore.Mvc.Controllers;
87
using Microsoft.AspNetCore.Mvc.ModelBinding;
8+
using Microsoft.AspNetCore.Mvc.Versioning;
9+
using Microsoft.Extensions.Options;
910
using System.Collections.Generic;
1011
using System.Diagnostics.Contracts;
1112
using System.Linq;
1213

1314
sealed class ODataActionDescriptorProvider : IActionDescriptorProvider
1415
{
1516
readonly IODataRouteCollectionProvider routeCollectionProvider;
16-
readonly ApplicationPartManager partManager;
1717
readonly IModelMetadataProvider modelMetadataProvider;
18+
readonly IOptions<ODataApiVersioningOptions> options;
1819

1920
public ODataActionDescriptorProvider(
2021
IODataRouteCollectionProvider routeCollectionProvider,
21-
ApplicationPartManager partManager,
22-
IModelMetadataProvider modelMetadataProvider )
22+
IModelMetadataProvider modelMetadataProvider,
23+
IOptions<ODataApiVersioningOptions> options )
2324
{
2425
Contract.Requires( routeCollectionProvider != null );
25-
Contract.Requires( partManager != null );
2626
Contract.Requires( modelMetadataProvider != null );
27+
Contract.Requires( options != null );
2728

2829
this.routeCollectionProvider = routeCollectionProvider;
29-
this.partManager = partManager;
3030
this.modelMetadataProvider = modelMetadataProvider;
31+
this.options = options;
3132
}
3233

3334
public int Order => 0;
@@ -45,7 +46,7 @@ public void OnProvidersExecuted( ActionDescriptorProviderContext context )
4546
var conventions = new IODataActionDescriptorConvention[]
4647
{
4748
new ImplicitHttpMethodConvention(),
48-
new ODataRouteBindingInfoConvention( routeCollectionProvider, modelMetadataProvider ),
49+
new ODataRouteBindingInfoConvention( routeCollectionProvider, modelMetadataProvider, options ),
4950
};
5051

5152
foreach ( var action in ODataActions( results ) )

src/Microsoft.AspNetCore.OData.Versioning/AspNetCore.Mvc/Versioning/ODataApiVersioningOptions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,11 @@ public ApiVersionConventionBuilder Conventions
3131
conventions = value;
3232
}
3333
}
34+
35+
/// <summary>
36+
/// Gets or sets a value indicating whether qualified names are used when building URLs.
37+
/// </summary>
38+
/// <value>True if qualified names are used when building URLs; otherwise, false. The default value is <c>false</c>.</value>
39+
public bool UseQualifiedNames { get; set; }
3440
}
3541
}

0 commit comments

Comments
 (0)