Skip to content

Commit 4457262

Browse files
Chris Martinezcommonsensesoftware
authored andcommitted
Fix key as segment URL generation. Fixes #526
1 parent 3badc7b commit 4457262

File tree

8 files changed

+29
-33
lines changed

8 files changed

+29
-33
lines changed

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

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using Microsoft.OData.Edm;
1010
using System;
1111
using System.Collections.Generic;
12-
using System.ComponentModel.DataAnnotations.Schema;
1312
using System.Diagnostics.Contracts;
1413
using System.Linq;
1514
using System.Reflection;
@@ -122,15 +121,18 @@ void AppendEntitySetOrOperationFromAttributes( IList<string> segments, string pr
122121

123122
if ( IsNullOrEmpty( prefix ) )
124123
{
125-
segments.Add( template );
124+
if ( !IsNullOrEmpty( template ) )
125+
{
126+
segments.Add( template );
127+
}
126128
}
127129
else
128130
{
129131
if ( IsNullOrEmpty( template ) )
130132
{
131133
segments.Add( prefix );
132134
}
133-
else if ( template[0] == '(' && Context.UrlKeyDelimiter == Parentheses )
135+
else if ( template[0] == '(' )
134136
{
135137
segments.Add( prefix + template );
136138
}
@@ -181,7 +183,7 @@ void AppendEntityKeysFromConvention( StringBuilder builder )
181183
var entityKeys = ( Context.EntitySet?.EntityType().Key() ?? Empty<IEdmStructuralProperty>() ).ToArray();
182184
var parameterKeys = Context.ParameterDescriptions.Where( p => p.Name.StartsWith( ODataRouteConstants.Key, OrdinalIgnoreCase ) ).ToArray();
183185

184-
if ( entityKeys.Length != parameterKeys.Length )
186+
if ( entityKeys.Length == 0 || entityKeys.Length != parameterKeys.Length )
185187
{
186188
return;
187189
}
@@ -203,16 +205,16 @@ void AppendEntityKeysFromConvention( StringBuilder builder )
203205

204206
if ( entityKeys.Length == 1 )
205207
{
206-
ExpandParameterTemplate( builder, entityKeys[0], ODataRouteConstants.Key );
208+
ExpandParameterTemplate( builder, entityKeys[0].Type, ODataRouteConstants.Key, keyAsSegment );
207209
}
208210
else
209211
{
210-
ExpandParameterTemplate( builder, entityKeys[0], parameterKeys[0].Name );
212+
ExpandParameterTemplate( builder, entityKeys[0].Type, parameterKeys[0].Name, keyAsSegment );
211213

212214
for ( var i = 1; i < entityKeys.Length; i++ )
213215
{
214216
builder.Append( keySeparator );
215-
ExpandParameterTemplate( builder, entityKeys[i], parameterKeys[i].Name, keyAsSegment );
217+
ExpandParameterTemplate( builder, entityKeys[i].Type, parameterKeys[i].Name, keyAsSegment );
216218
}
217219
}
218220

@@ -283,12 +285,6 @@ void AppendParametersFromConvention( StringBuilder builder, IEdmOperation operat
283285
}
284286
}
285287

286-
void ExpandParameterTemplate( StringBuilder template, IEdmStructuralProperty key ) =>
287-
ExpandParameterTemplate( template, key.Type, key.Name, keyAsSegment: false );
288-
289-
void ExpandParameterTemplate( StringBuilder template, IEdmStructuralProperty key, string name, bool keyAsSegment = false ) =>
290-
ExpandParameterTemplate( template, key.Type, name, keyAsSegment );
291-
292288
void ExpandParameterTemplate( StringBuilder template, IEdmOperationParameter parameter, string name ) =>
293289
ExpandParameterTemplate( template, parameter.Type, name, keyAsSegment: false );
294290

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using System.Web.Http.Dispatcher;
2424
using ControllerActionDescriptor = System.Web.Http.Controllers.HttpActionDescriptor;
2525
#endif
26+
using static Microsoft.OData.ODataUrlKeyDelimiter;
2627
using static ODataRouteTemplateGenerationKind;
2728

2829
sealed partial class ODataRouteBuilderContext
@@ -99,5 +100,9 @@ internal static ODataRouteActionType GetActionType( IEdmEntitySet entitySet, IEd
99100

100101
return ODataRouteActionType.Unknown;
101102
}
103+
104+
// Slash became the default 4/18/2018
105+
// REF: https://github.com/OData/WebApi/pull/1393
106+
static ODataUrlKeyDelimiter UrlKeyDelimiterOrDefault( ODataUrlKeyDelimiter urlKeyDelimiter ) => urlKeyDelimiter ?? Slash;
102107
}
103108
}

src/Microsoft.AspNet.OData.Versioning.ApiExplorer/AspNet.OData/Routing/ODataRouteBuilderContext.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using System.Web.Http;
1313
using System.Web.Http.Controllers;
1414
using System.Web.Http.Description;
15-
using static Microsoft.OData.ODataUrlKeyDelimiter;
1615
using static System.Linq.Enumerable;
1716

1817
partial class ODataRouteBuilderContext
@@ -43,7 +42,7 @@ internal ODataRouteBuilderContext(
4342
ActionDescriptor = actionDescriptor;
4443
ParameterDescriptions = parameterDescriptions;
4544
Options = options;
46-
UrlKeyDelimiter = configuration.GetUrlKeyDelimiter() ?? Parentheses;
45+
UrlKeyDelimiter = UrlKeyDelimiterOrDefault( configuration.GetUrlKeyDelimiter() );
4746

4847
var container = EdmModel.EntityContainer;
4948

src/Microsoft.AspNet.OData.Versioning.ApiExplorer/System.Web.Http/HttpConfigurationExtensions.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
{
33
using Microsoft;
44
using Microsoft.OData;
5-
using Microsoft.Web.Http;
65
using Microsoft.Web.Http.Description;
76
using System.Collections.Concurrent;
87
using System.Diagnostics.Contracts;
@@ -70,12 +69,12 @@ internal static ODataUrlKeyDelimiter GetUrlKeyDelimiter( this HttpConfiguration
7069
{
7170
Contract.Requires( configuration != null );
7271

73-
if ( configuration.Properties.TryGetValue( UrlKeyDelimiterKey, out var value ) && value is ODataUrlKeyDelimiter delimiter )
72+
if ( configuration.Properties.TryGetValue( UrlKeyDelimiterKey, out var value ) )
7473
{
75-
return delimiter;
74+
return value as ODataUrlKeyDelimiter;
7675
}
7776

78-
return ODataUrlKeyDelimiter.Parentheses;
77+
return default;
7978
}
8079
}
8180
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using System.Collections.Generic;
1111
using System.Diagnostics.Contracts;
1212
using System.Reflection;
13-
using static Microsoft.OData.ODataUrlKeyDelimiter;
1413
using static System.Linq.Enumerable;
1514

1615
partial class ODataRouteBuilderContext
@@ -35,7 +34,7 @@ internal ODataRouteBuilderContext(
3534
ActionDescriptor = actionDescriptor;
3635
ParameterDescriptions = new List<ApiParameterDescription>();
3736
Options = options;
38-
UrlKeyDelimiter = serviceProvider.GetRequiredService<ODataOptions>().UrlKeyDelimiter ?? Parentheses;
37+
UrlKeyDelimiter = UrlKeyDelimiterOrDefault( serviceProvider.GetRequiredService<ODataOptions>().UrlKeyDelimiter );
3938

4039
var container = EdmModel.EntityContainer;
4140

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using System;
1010
using System.Diagnostics.Contracts;
1111
using System.Reflection;
12-
using static Microsoft.OData.ODataUrlKeyDelimiter;
1312
using static System.Linq.Enumerable;
1413

1514
partial class ODataRouteBuilderContext
@@ -33,7 +32,7 @@ internal ODataRouteBuilderContext(
3332
Route = routeMapping.Route;
3433
ActionDescriptor = actionDescriptor;
3534
Options = options;
36-
UrlKeyDelimiter = serviceProvider.GetRequiredService<ODataOptions>().UrlKeyDelimiter ?? Parentheses;
35+
UrlKeyDelimiter = UrlKeyDelimiterOrDefault( serviceProvider.GetRequiredService<ODataOptions>().UrlKeyDelimiter );
3736

3837
var container = EdmModel.EntityContainer;
3938

test/Microsoft.AspNetCore.OData.Versioning.ApiExplorer.Tests/AspNetCore.Mvc.ApiExplorer/ODataApiDescriptionProviderTest.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private void AssertVersion0_9( ApiDescriptionGroup group )
5858
{
5959
new { HttpMethod = "GET", GroupName, RelativePath = "api/GetSalesTaxRate(PostalCode={postalCode})" },
6060
new { HttpMethod = "GET", GroupName, RelativePath = "api/Orders({key})" },
61-
new { HttpMethod = "GET", GroupName, RelativePath = "api/People({key})" },
61+
new { HttpMethod = "GET", GroupName, RelativePath = "api/People/{key}" },
6262
},
6363
options => options.ExcludingMissingMembers() );
6464
}
@@ -75,7 +75,7 @@ private void AssertVersion1( ApiDescriptionGroup group )
7575
new { HttpMethod = "GET", GroupName, RelativePath = "api/Orders({key})" },
7676
new { HttpMethod = "POST", GroupName, RelativePath = "api/Orders" },
7777
new { HttpMethod = "GET", GroupName, RelativePath = "api/Orders/MostExpensive" },
78-
new { HttpMethod = "GET", GroupName, RelativePath = "api/People({key})" },
78+
new { HttpMethod = "GET", GroupName, RelativePath = "api/People/{key}" },
7979
},
8080
options => options.ExcludingMissingMembers() );
8181
}
@@ -96,7 +96,7 @@ private void AssertVersion2( ApiDescriptionGroup group )
9696
new { HttpMethod = "GET", GroupName, RelativePath = "api/Orders/MostExpensive" },
9797
new { HttpMethod = "POST", GroupName, RelativePath = "api/Orders({key})/Rate" },
9898
new { HttpMethod = "GET", GroupName, RelativePath = "api/People" },
99-
new { HttpMethod = "GET", GroupName, RelativePath = "api/People({key})" },
99+
new { HttpMethod = "GET", GroupName, RelativePath = "api/People/{key}" },
100100
new { HttpMethod = "GET", GroupName, RelativePath = "api/People/NewHires(Since={since})" },
101101
},
102102
options => options.ExcludingMissingMembers() );
@@ -121,10 +121,10 @@ private void AssertVersion3( ApiDescriptionGroup group )
121121
new { HttpMethod = "GET", GroupName, RelativePath = "api/Orders/MostExpensive" },
122122
new { HttpMethod = "POST", GroupName, RelativePath = "api/Orders({key})/Rate" },
123123
new { HttpMethod = "GET", GroupName, RelativePath = "api/People" },
124-
new { HttpMethod = "GET", GroupName, RelativePath = "api/People({key})" },
124+
new { HttpMethod = "GET", GroupName, RelativePath = "api/People/{key}" },
125125
new { HttpMethod = "POST", GroupName, RelativePath = "api/People" },
126126
new { HttpMethod = "GET", GroupName, RelativePath = "api/People/NewHires(Since={since})" },
127-
new { HttpMethod = "POST", GroupName, RelativePath = "api/People({key})/Promote" },
127+
new { HttpMethod = "POST", GroupName, RelativePath = "api/People/{key}/Promote" },
128128
},
129129
options => options.ExcludingMissingMembers() );
130130
}

test/directory.build.props

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,15 @@
1414
</ItemGroup>
1515

1616
<ItemGroup Condition=" '$(MSBuildProjectExtension)' != '.shproj' ">
17-
<PackageReference Include="FluentAssertions" Version="5.5.3" />
18-
<PackageReference Include="Moq" Version="4.10.1" />
17+
<PackageReference Include="FluentAssertions" Version="5.7.0" />
18+
<PackageReference Include="Moq" Version="4.12.0" />
1919
<PackageReference Include="xunit" Version="2.4.1" />
2020
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
2121
</ItemGroup>
2222

2323
<ItemGroup Condition=" '$(IsAspNetCore)' == 'true' ">
24-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
25-
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.1.1" />
24+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
25+
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.2.0" />
2626
</ItemGroup>
2727

28-
2928
</Project>

0 commit comments

Comments
 (0)