-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Implement RouteHandlerServices.Map and use in RequestDelegateGenerator #46180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -174,239 +157,5 @@ internal static Task ExecuteObjectResult(object? obj, HttpContext httpContext) | |||
} | |||
} | |||
} | |||
|
|||
{{GeneratedCodeAttribute}} | |||
file class SourceGeneratedRouteEndpointDataSource : EndpointDataSource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥇
e2c1815
to
6327fcf
Compare
builder.Metadata.Add(new SourceKey{{StaticRouteHandlerModelEmitter.EmitSourceKey(endpoint)}}); | ||
if (options == null) | ||
{ | ||
return new RequestDelegateMetadataResult { EndpointMetadata = new List<object>().AsReadOnly() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
Replace new List<object>().AsReadOnly()
with ReadOnlyCollection<object>.Empty
, at least 3 places can be changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL! Looks like this was added in 8.0? Very nice...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I just assumed it existed and saw that it did 😄
Didn't realize it's new!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the same comment, but you can use Array.Empty<object>()
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up using ReadOnlyCollection<object>
. In the interest of readability it does a better job of communicating the type passed to the initializer here and I don't think there's any memory implications with that singleton.
src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs
Outdated
Show resolved
Hide resolved
src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateGeneratorTests.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome work, @captainsafia.
I feel like I'm better able to give a decent code review now that I can see the generated code.
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
|
||
}; | ||
|
||
%GENERATEDCODEATTRIBUTE% |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar comment as above. Do we need this attribute on these methods when the whole class is marked as generated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noodled on our use of the GeneratedCode
attribute here a little bit more. Since the primary goal of the attribute is to make it easier to inspect if a type is codegenned from metadata, I think it makes sense to only include it in types that could be referenced from user code. Specifically, this would be:
- The
SourceKey
definition - The strongly-typed
Map
overloads
I refactored the code to apply it to these places. Note, I opted to remove it from the static class containing the strongly-typed Map
overloads since it's unlikely that user code ends up resolving that directly.
Let me know if you think this philosophy makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we want the GeneratedCodeAttribute
on all the classes we generate in this file.
The reason is so things like analyzers, code-style, and code coverage tools don't warn/report things from inside this code. The devs can't change this code, so they shouldn't see tools talking about.
Even for the internal static class GenerateRouteBuilderEndpoints
class. The Regex generator puts it on the partial methods, and not the class, because the class is partial to the user's code. So it would be incorrect to put it on the whole class, since the user writes code in this class too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Regex generator puts it on the partial methods, and not the class, because the class is partial to the user's code. So it would be incorrect to put it on the whole class, since the user writes code in this class too.
This insights makes sense to me.
Here's the modification I made:
- Moved the
GenerateRouteBuilderEndpoints
to the code generated in theMicrosoft.AspNetCore.Builder
namespace to fix theglobal::
using issue - Added the
GeneratedCode
attribute to theGenerateRouteBuilderEndpoints
class
So, all the classes we codegen inside that namespacce are marked.
Classes marked as file private
are not marked, which I assume is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Classes marked as file private are not marked, which I assume is fine.
I think they should be marked as well. That way they don't show up in code coverage reports, that devs can't do anything about.
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
// </auto-generated> | ||
//------------------------------------------------------------------------------ | ||
#nullable enable | ||
using global::Microsoft.AspNetCore.Http; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this using left for? I assume it shouldn't be needed, since everything outside of the namespace Microsoft.AspNetCore.Http.Generated
should be fully qualified.
|
||
}; | ||
|
||
%GENERATEDCODEATTRIBUTE% |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we want the GeneratedCodeAttribute
on all the classes we generate in this file.
The reason is so things like analyzers, code-style, and code coverage tools don't warn/report things from inside this code. The devs can't change this code, so they shouldn't see tools talking about.
Even for the internal static class GenerateRouteBuilderEndpoints
class. The Regex generator puts it on the partial methods, and not the class, because the class is partial to the user's code. So it would be incorrect to put it on the whole class, since the user writes code in this class too.
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
...test/RequestDelegateGenerator/Baselines/MapGet_NoParam_StringReturn_WithFilter.generated.txt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for fixing all my nits. :) I think the code gen looks really clean now.
private static void PopulateMetadata<T>(MethodInfo method, EndpointBuilder builder) where T : IEndpointMetadataProvider | ||
{ | ||
T.PopulateMetadata(method, builder); | ||
} | ||
|
||
private static void PopulateMetadata<T>(ParameterInfo parameter, EndpointBuilder builder) where T : IEndpointParameterMetadataProvider | ||
{ | ||
T.PopulateMetadata(parameter, builder); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see these methods used. I assume they will be used in the future. Not a huge deal, but in the future we might want to only generate them if they are actually being used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes 🙊 ... we'll eventually use this when we add support for populating metadata for types that implement the IEndpointMetadataProvider
interfaces. I can remove it in the next PR...
dotnet#46180) * Implement RouteHandlerServices.Map and use in RequestDelegateGenerator * Tweak generated code * Remove warnings from generated code * Fix docstring for RouteHandlerServices.Map * Add baseline tests and fix global:: issue * Clean up generated code * Add HTTP verb caching and fix usings * Use FQN and remove GeneratedCode attribute
Addresses #46163
RouteHandlerServices.Map
implementation per API review aboveSourceGeneratorEndpointDataSource
implementation in RequestDelegateGenerator's outputIEndpointRouteBuilder.GetOrAddRouteEndpointDataSource
internal to support invocation fromRouteHandlerServices.Map
RouteHandlerServices.Map