From 32b9b0a0ee1dae7e431f6483667eccb07f419e69 Mon Sep 17 00:00:00 2001 From: Sam Xu Date: Wed, 9 Aug 2023 16:10:55 -0700 Subject: [PATCH] fixes #986: add Order for conventional, fixes the failing test, update the sample --- .../Controllers/CustomersController.cs | 1 + sample/ODataAlternateKeySample/readme.md | 6 +++--- .../Extensions/ActionModelExtensions.cs | 1 + .../Microsoft.AspNetCore.OData.xml | 6 ++++++ src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt | 2 ++ src/Microsoft.AspNetCore.OData/Routing/ODataRouteOptions.cs | 5 +++++ .../AlternateKeys/AlternateKeysController.cs | 6 +++++- .../PublicApi/Microsoft.AspNetCore.OData.PublicApi.Net6.bsl | 1 + .../Microsoft.AspNetCore.OData.PublicApi.NetCore31.bsl | 1 + 9 files changed, 25 insertions(+), 4 deletions(-) diff --git a/sample/ODataAlternateKeySample/Controllers/CustomersController.cs b/sample/ODataAlternateKeySample/Controllers/CustomersController.cs index 84f93b415..8cd6c2874 100644 --- a/sample/ODataAlternateKeySample/Controllers/CustomersController.cs +++ b/sample/ODataAlternateKeySample/Controllers/CustomersController.cs @@ -54,6 +54,7 @@ public IActionResult Post([FromBody]Customer c) [HttpGet("odata/Customers(CoreSN={ssn})")] // use core alternate key public IActionResult GetCustomerBySSN(string ssn) { + ssn = ssn.Replace("%", "%25"); var c = _repository.GetCustomers().FirstOrDefault(c => c.SSN == ssn); if (c == null) { diff --git a/sample/ODataAlternateKeySample/readme.md b/sample/ODataAlternateKeySample/readme.md index 593db7598..f40f436c3 100644 --- a/sample/ODataAlternateKeySample/readme.md +++ b/sample/ODataAlternateKeySample/readme.md @@ -207,8 +207,8 @@ Send one of the following requests ```C# GET http://localhost:5219/odata/Customers(2) -GET http://localhost:5219/odata/Customers(SSN='SSN-2-102') -GET http://localhost:5219/odata/Customers(CoreSN='SSN-2-102') +GET http://localhost:5219/odata/Customers(SSN='SSN-%25-2-102') +GET http://localhost:5219/odata/Customers(CoreSN='SSN-%25-2-102') ``` you can get the following result: @@ -217,7 +217,7 @@ you can get the following result: "@odata.context": "http://localhost:5219/odata/$metadata#Customers/$entity", "Id": 2, "Name": "Jerry", - "SSN": "SSN-2-102", + "SSN": "SSN-%25-2-102", "Titles": [ "abc", null, diff --git a/src/Microsoft.AspNetCore.OData/Extensions/ActionModelExtensions.cs b/src/Microsoft.AspNetCore.OData/Extensions/ActionModelExtensions.cs index 788b177ca..ddf4b3d8c 100644 --- a/src/Microsoft.AspNetCore.OData/Extensions/ActionModelExtensions.cs +++ b/src/Microsoft.AspNetCore.OData/Extensions/ActionModelExtensions.cs @@ -215,6 +215,7 @@ public static void AddSelector(this ActionModel action, string httpMethods, stri // OData convention route template doesn't get combined with the route template applied to the controller. // Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller. Template = $"/{templateStr}", + Order = options?.Order, Name = templateStr // do we need this? }; diff --git a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml index 90f8e731c..7c2c27502 100644 --- a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml +++ b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml @@ -13953,6 +13953,12 @@ Initializes a new instance of the class. + + + Gets or sets the route order in conventional routing. + By default, move the conventional routing later as much as possible. + + Gets/sets a value indicating whether to enable $count in conventional routing. diff --git a/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt b/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt index f918ce0cf..54790de77 100644 --- a/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt +++ b/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt @@ -1353,6 +1353,8 @@ Microsoft.AspNetCore.OData.Routing.ODataRouteOptions.EnableQualifiedOperationCal Microsoft.AspNetCore.OData.Routing.ODataRouteOptions.EnableUnqualifiedOperationCall.get -> bool Microsoft.AspNetCore.OData.Routing.ODataRouteOptions.EnableUnqualifiedOperationCall.set -> void Microsoft.AspNetCore.OData.Routing.ODataRouteOptions.ODataRouteOptions() -> void +Microsoft.AspNetCore.OData.Routing.ODataRouteOptions.Order.get -> int? +Microsoft.AspNetCore.OData.Routing.ODataRouteOptions.Order.set -> void Microsoft.AspNetCore.OData.Routing.ODataRoutingMetadata Microsoft.AspNetCore.OData.Routing.ODataRoutingMetadata.IsConventional.get -> bool Microsoft.AspNetCore.OData.Routing.ODataRoutingMetadata.IsConventional.set -> void diff --git a/src/Microsoft.AspNetCore.OData/Routing/ODataRouteOptions.cs b/src/Microsoft.AspNetCore.OData/Routing/ODataRouteOptions.cs index 28c2e1b32..e5ecc9fb5 100644 --- a/src/Microsoft.AspNetCore.OData/Routing/ODataRouteOptions.cs +++ b/src/Microsoft.AspNetCore.OData/Routing/ODataRouteOptions.cs @@ -33,6 +33,11 @@ public ODataRouteOptions() _enableUnqualifiedOperationCall = true; } + /// + /// Gets or sets the route order in conventional routing. + /// + public int? Order { get; set; } + /// /// Gets/sets a value indicating whether to enable $count in conventional routing. /// diff --git a/test/Microsoft.AspNetCore.OData.E2E.Tests/AlternateKeys/AlternateKeysController.cs b/test/Microsoft.AspNetCore.OData.E2E.Tests/AlternateKeys/AlternateKeysController.cs index 021318e32..0886a9ccd 100644 --- a/test/Microsoft.AspNetCore.OData.E2E.Tests/AlternateKeys/AlternateKeysController.cs +++ b/test/Microsoft.AspNetCore.OData.E2E.Tests/AlternateKeys/AlternateKeysController.cs @@ -38,7 +38,11 @@ public IActionResult Get(int key) } // alternate key: SSN - [HttpGet("Customers(SSN={ssn})", Order = 2)] + // why set Order = -2 (any number less than 0)? it is because 'Get' method has 'catch-all' template, we should move this template ahead + // Small order goes first. + // We can also leave order value unset, same as 'Get' method and 'PatchCustomerBySSN' method without setting the order value. + // Without setting the order value makes all routes with same order value and catch-all goes latter + [HttpGet("Customers(SSN={ssn})", Order = -2)] public IActionResult GetCustomerBySSN(string ssn) { // for special test diff --git a/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.Net6.bsl b/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.Net6.bsl index d7a0a7edb..3c76e3065 100644 --- a/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.Net6.bsl +++ b/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.Net6.bsl @@ -1868,6 +1868,7 @@ public class Microsoft.AspNetCore.OData.Routing.ODataRouteOptions { bool EnablePropertyNameCaseInsensitive { public get; public set; } bool EnableQualifiedOperationCall { public get; public set; } bool EnableUnqualifiedOperationCall { public get; public set; } + System.Nullable`1[[System.Int32]] Order { public get; public set; } } public sealed class Microsoft.AspNetCore.OData.Routing.ODataRoutingMetadata : IODataRoutingMetadata { diff --git a/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.NetCore31.bsl b/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.NetCore31.bsl index d7a0a7edb..3c76e3065 100644 --- a/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.NetCore31.bsl +++ b/test/Microsoft.AspNetCore.OData.Tests/PublicApi/Microsoft.AspNetCore.OData.PublicApi.NetCore31.bsl @@ -1868,6 +1868,7 @@ public class Microsoft.AspNetCore.OData.Routing.ODataRouteOptions { bool EnablePropertyNameCaseInsensitive { public get; public set; } bool EnableQualifiedOperationCall { public get; public set; } bool EnableUnqualifiedOperationCall { public get; public set; } + System.Nullable`1[[System.Int32]] Order { public get; public set; } } public sealed class Microsoft.AspNetCore.OData.Routing.ODataRoutingMetadata : IODataRoutingMetadata {