- 
                Notifications
    
You must be signed in to change notification settings  - Fork 10.5k
 
Expand FromX support and add route vs. query param inference #46715
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
c5d5681    to
    9e15ee2      
    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.
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
        
      | 
               | 
          ||
| // Preamble for diagnostics purposes. | ||
| 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.
(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; | ||
| } | ||
| 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.
FromRouteandFromHeaderattributeNameargument on attributesNameargument inFromQueryattributeFromQueryattributesSharedTypesinstead of types in test source