[Endpoint routing review]First draft to enable endpoint routing using dynamic controller - #2035
Conversation
831209c to
8d9c27b
Compare
| } | ||
|
|
||
| querySettings = defaultQuerySettings; | ||
| } |
There was a problem hiding this comment.
How does this even work? #Closed
There was a problem hiding this comment.
|
|
||
| querySettings = defaultQuerySettings; | ||
| builder.ServiceProvider.SetDefaultQuerySettings(defaultQuerySettings); | ||
| return builder; |
There was a problem hiding this comment.
What is the reason behind this change? Extension method for service provider is not intuitive. May be you want to create a private static methods rather than extension methods. #WontFix
There was a problem hiding this comment.
| using Microsoft.AspNetCore.Mvc.Infrastructure; | ||
| using Microsoft.AspNetCore.Routing; | ||
| #if NETCOREAPP3_1 | ||
| using Microsoft.AspNetCore.Routing.Matching; |
There was a problem hiding this comment.
Once we upgrade to higher versions of net core, this would need to be changed right? Is there a conditional compile that specifies greater than? #Resolved
There was a problem hiding this comment.
| @@ -39,23 +38,7 @@ public static IRouteBuilder SetDefaultQuerySettings(this IRouteBuilder builder, | |||
| throw Error.ArgumentNull("builder"); | |||
| } | |||
There was a problem hiding this comment.
Now I understand the reason for this change. I still feel extension method may not be right. Just a shared static method with a normal parameter may be better. #WontFix
There was a problem hiding this comment.
Extension method, we can call the method using Fluent way.
builder.Fun1().Func2().Func3()....
with static method. we can't do like this.
In reply to: 375990865 [](ancestors = 375990865)
| /// <param name="model">The EDM model to use for parsing OData paths.</param> | ||
| /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> | ||
| /// <returns>The <see cref="IEndpointRouteBuilder"/>.</returns> | ||
| public static IEndpointRouteBuilder MapODataRoute(this IEndpointRouteBuilder builder, |
There was a problem hiding this comment.
MapODataRoute [](start = 44, length = 13)
You should use MapODataServiceRoute to maintain parity. #Resolved
| /// The OData routing conventions to use for controller and action selection. | ||
| /// </param> | ||
| /// <returns>The <see cref="IEndpointRouteBuilder"/>.</returns> | ||
| public static IEndpointRouteBuilder MapODataRoute(this IEndpointRouteBuilder builder, |
There was a problem hiding this comment.
MapODataRoute [](start = 44, length = 13)
Same for other. Change the name. #Resolved
| <VersionMinor Condition="'$(VersionMinor)' == ''">4</VersionMinor> | ||
| <VersionBuild Condition="'$(VersionBuild)' == ''">0</VersionBuild> | ||
| <VersionRelease Condition="'$(VersionRelease)' == ''"></VersionRelease> | ||
| </PropertyGroup> |
There was a problem hiding this comment.
Add beta here. #Resolved
| if (start == -1 || end == -1) | ||
| { | ||
| break; | ||
| } |
There was a problem hiding this comment.
I am missing something may be. It seems that the if prefix has '{' and '}', this will loop indefinitely as prefix never changes. #WontFix
There was a problem hiding this comment.
| foreach (var item in templates) | ||
| { | ||
| string variable = item.Substring(1, item.Length - 2); // remove { and } | ||
|
|
There was a problem hiding this comment.
Why substring again? We should add to templates after striping the braces already. #WontFix
There was a problem hiding this comment.
We only replace the string within "{" and "}". and keep the other as it. for example:
prefix: "data{data}" and we have {"data": 1} in route value, the return of this method should be "data1", not "11". See more from my added test cases.
In reply to: 376002864 [](ancestors = 376002864)
| private static string UriEncode(string str) | ||
| { | ||
| string escape = Uri.EscapeUriString(str); | ||
| escape = escape.Replace("#", _escapedHashMark); |
There was a problem hiding this comment.
"#" [](start = 36, length = 3)
Declare these strings as constants? It may be better to use the char overload instead of the string overload for better performance. #Pending
There was a problem hiding this comment.
Replace doesn't have a overload to replace a char in a string. and for better readability, I'd like to use "#" directly here. The LinkGenerator mayeb change later.
In reply to: 376006516 [](ancestors = 376006516)
|
|
||
| /// <inheritdoc/> | ||
| public override Task SelectAsync(HttpContext httpContext, CandidateSet candidateSet) | ||
| { |
There was a problem hiding this comment.
What are the other things that can happen in the pipeline while this runs asynchronously?
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| #if !NETSTANDARD2_0 |
There was a problem hiding this comment.
!NETSTANDARD2_0 [](start = 4, length = 15)
This conditional is different from the other conditional. Can you explain the reason? #Resolved
|
I see the sample but there are no test cases. Can you please add test cases for endpoint routing? Specially for the ones where controller methods are overloaded? #Resolved |
| /// </summary> | ||
| internal class ODataEndpointSelector : EndpointSelector | ||
| { | ||
| private EndpointSelector _innerSelector; |
There was a problem hiding this comment.
_innerSelector [](start = 33, length = 14)
I am unclear on what does the coding style guidelines say about using _ for private members. It was the old naming convention and I see that not all classes use this. We should discuss what is the recommendation, since this convention is different in ODL as well.
5229452 to
59b98be
Compare
| /// <param name="generator">The inner Link generator</param> | ||
| public ODataEndpointLinkGenerator(LinkGenerator generator) | ||
| { | ||
| _innerGenerator = generator; |
There was a problem hiding this comment.
@xuzhg Is there a chance of this constructor being called with a null value for the LinkGenerator parameter? That would most certainly precipitate chaos when the overridden methods that reference _innerGenerator are called #Resolved
There was a problem hiding this comment.
Theoretically, no. But, let me add the verification code.
In reply to: 384365505 [](ancestors = 384365505)
| { | ||
| if (routeName == null) | ||
| { | ||
| throw Error.ArgumentNull("routeName"); |
| { | ||
| if (comparer == null) | ||
| { | ||
| throw new ArgumentNullException(nameof(comparer)); |
| { | ||
| if (serviceProvider == null) | ||
| { | ||
| throw Error.ArgumentNull("serviceProvider"); |
| { | ||
| if (serviceProvider == null) | ||
| { | ||
| throw Error.ArgumentNull("serviceProvider"); |
|
|
||
| DefaultQuerySettings defaultQuerySettings = builder.GetDefaultQuerySettings(); | ||
| defaultQuerySettings.EnableCount = true; | ||
| builder.ServiceProvider.Count(); |
There was a problem hiding this comment.
Thanks. I forgot to change that Count(...) method. Fixed.
In reply to: 384452658 [](ancestors = 384452658)
| throw Error.ArgumentNull("routeName"); | ||
| } | ||
|
|
||
| IList<IODataRoutingConvention> routingConventions = CreateDefault(); |
There was a problem hiding this comment.
@xuzhg The 4 lines here are a replica of these others here. Maybe the existing CreateDefaultWithAttributeRouting overload could call this new one like this return CreateDefaultWithAttributeRouting(routeName, builder.ServiceProvider) - in which case the check for null routeName wouldn't be required in the existing overload, or consider adding a helper private method that both overloads call #Resolved
There was a problem hiding this comment.
There was a problem hiding this comment.
Changed.
Originally, i'd like to change the exiting public to the new one. However, it's a breaking change. So, i add a new one.
In reply to: 384715327 [](ancestors = 384715327,384475452)
Given that we are adding to a public interface, I assume we don't expect anyone to have their own custom implementations of this interface that would now break? #Pending Refers to: src/Microsoft.AspNetCore.OData/Interfaces/IODataFeature.cs:20 in 59b98be. [](commit_id = 59b98be, deletion_comment = False) |
| @@ -11,6 +11,20 @@ namespace Microsoft.AspNet.OData | |||
| /// </summary> | |||
| public interface IPerRouteContainer | |||
There was a problem hiding this comment.
public [](start = 4, length = 6)
I assume there are no custom implementations that would break by our adding members to this interface? #Pending
There was a problem hiding this comment.
| // : this((EndpointDataSource)dataSource) | ||
| // { | ||
| // } | ||
| //} |
There was a problem hiding this comment.
clean this up?
#Resolved
|
Added the test cases In reply to: 583046981 [](ancestors = 583046981) |
We have been discussing about to add the public interface for a long time. It seems it's not a breaking change to add new items to a public interface. However, you are right. We don't expect any customer to create their own custom "IODataFeature" implementation. In reply to: 591585939 [](ancestors = 591585939) Refers to: src/Microsoft.AspNetCore.OData/Interfaces/IODataFeature.cs:20 in 59b98be. [](commit_id = 59b98be, deletion_comment = False) |
c1089ca to
3c9aa37
Compare
… dynamic controller (#2035) * Enable endpoint routing using dynamic controller * Update to 7.4.0 * Update the PublicAPI test cases * Add the E2E test cases * Change the startup to test the per-route configuration * Some test codes about policy * Use MatcherPolicy Instead of EndpointSelector to resolve the ambiguity * Address the comments and add LinkGenerator test cases * Revert the EF Core version to 2.2.0 to make Aggregation E2E test pass
… dynamic controller (OData#2035) * Enable endpoint routing using dynamic controller * Update to 7.4.0 * Update the PublicAPI test cases * Add the E2E test cases * Change the startup to test the per-route configuration * Some test codes about policy * Use MatcherPolicy Instead of EndpointSelector to resolve the ambiguity * Address the comments and add LinkGenerator test cases * Revert the EF Core version to 2.2.0 to make Aggregation E2E test pass
Issues
This pull request fixes issue #xxx.
Description
Checklist (Uncheck if it is not completed)
Additional work necessary
If documentation update is needed, please add "Docs Needed" label to the issue and provide details about the required document change in the issue.