-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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
Expand FromX support and add route vs. query param inference #46715
Conversation
c5d5681
to
9e15ee2
Compare
@@ -9,11 +9,11 @@ internal static class EndpointParameterEmitter | |||
internal static string EmitSpecialParameterPreparation(this EndpointParameter endpointParameter) | |||
{ | |||
return $""" | |||
var {endpointParameter.Name}_local = {endpointParameter.AssigningCode}; | |||
var {endpointParameter.HandlerArgument} = {endpointParameter.AssigningCode}; |
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'm starting to get a bit concerned about the tight coupling between EndpointParameterEmitter
and EndpointParameter
(and friends). It is starting to seem to me like we should just collapse the types together and just have a method on EndpointParameter to emit the block of code.
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 was actually thinking the other way around. EndpointParameter
should be strictly about processing syntax to set state on the parameter objects and EndpointParameterEmitter
should handle constructing the blocks of code.
I'll add a commit to showcase what this might look like.
@dotnet/minimal-apis Can I get a review? 🙏🏽 |
...DelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt
Outdated
Show resolved
Hide resolved
...DelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt
Outdated
Show resolved
Hide resolved
src/Http/Http.Extensions/test/RequestDelegateGenerator/SharedTypes.cs
Outdated
Show resolved
Hide resolved
var updatedSource = @"app.MapGet(""/"", ([FromBody] Todo? todo) => TypedResults.Ok(todo));"; | ||
var source = $"""app.MapGet("/", ([{typeof(FromBodyAttribute)}] {typeof(Todo)} todo) => TypedResults.Ok(todo));"""; | ||
var updatedSource = $""" | ||
#pragma warning disable CS8622 |
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.
For my learning, why do we get this warning here?
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 a result of the bug outlined in #46622
src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateGeneratorTests.cs
Outdated
Show resolved
Hide resolved
var value_raw = GeneratedRouteBuilderExtensionsCore.ResolveFromRouteOrQuery(httpContext, "value", options?.RouteParameterNames); | ||
var value_local = value_raw; |
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.
Why do we need value_local
here?
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 meant to indicate where the TryParse
code in #46696 would go. It mostly exists to make rebasing easier since we'll need to support TryParse
on parameters from multiple sources.
...uestDelegateGenerator/Baselines/MapAction_ExplicitSource_SimpleReturn_Snapshot.generated.txt
Show resolved
Hide resolved
src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs
Show resolved
Hide resolved
src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs
Outdated
Show resolved
Hide resolved
@@ -87,15 +153,31 @@ internal static string EmitServiceParameterPreparation(this EndpointParameter en | |||
{endpointParameter.EmitParameterDiagnosticComment()} |
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 on existing code)
Does this need to be wrapped in a """
string? Why can't it just be:
builder.AppendLine(endpointParameter.EmitParameterDiagnosticComment());
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.
Indentation! 😢
But see #46845 for some goodies.
- Add support for EmpyBodyBehavior check - Update source snapshots to implicit tests - Avoid codegenning `TryResolveRouteOrQuery` if not needed - Clean up test types
802218a
to
e47e69d
Compare
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. I just had a few more minor comments.
if (namedArgument.Key == argumentName) | ||
{ | ||
var routeParameterNameConstant = namedArgument.Value; | ||
argumentValue = (T)routeParameterNameConstant.Value!; |
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 if the argument is set to null
? Are we sure this will always be non null?
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.
Ah, good call! Yes, it's possible to do something like [FromQuery(Name = null)]
for example. I updated the implementation here and added a guard against this scenario.
Sidenote: I think this is a bug in the RDF, but we'll find out in #46838
...DelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt
Outdated
Show resolved
Hide resolved
...DelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt
Outdated
Show resolved
Hide resolved
src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs
Outdated
Show resolved
Hide resolved
} | ||
return false; | ||
isOptional |= fromBodyAttribute.TryGetNamedArgumentValue<int>("EmptyBodyBehavior", out var emptyBodyBehaviorValue) && emptyBodyBehaviorValue == 1; |
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.
Does this code still handle a custom IFromBodyMetadata attribute when the AllowEmpty
property is set in the attribute?
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 was a little iffy on whether or not we should support both. We use the custom FromBodyAttribute
implementation in our RDF tests (ref) but I don't think this is a common pattern in user code.
I ended up adding it back since we're not in a position to support FromBody
vs. FromService
inference and might need to implement a FromBody
attribute in our own source to avoid importing the Mvc namespace.
- Guard parameter name from attribute against null values - Support FromBody with AllowEmpty named argument
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
Part of #46275.
FromRoute
andFromHeader
attributeName
argument on attributesName
argument inFromQuery
attributeFromQuery
attributesSharedTypes
instead of types in test source