-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Fix for: Minimal APIs and controllers treat header arrays differently #58251
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
There is an active PR for this that has gone through some review and iterations. If you want to work on this bug you should check with the original PR author and see if they aren't going to work on their fix anymore so that you can take over. |
My bad. I've asked him just now. |
Thanks for checking with them, looks like you're good to go. I'd recommend taking a look at their PR and the reviews that took place to get an idea of what the current change might be missing. |
Confirmation would be appreciated
Confirmation would be appreciated |
The Request Delegate Generator is the source generator implementation that compiles arbitrary delegates to RequestDelegates when you are using native AoT. The behavior between the source generator and non-source generator based implementations should be the same which is why I provided that feedback.
This error comes from our analyzers. We'll probably want to update them so they account for the expanded support. Also, FWIW, I do think it is probably sufficient for us to just support arrays in this binding since that's what we do elsewhere for parameters. |
@captainsafia |
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.
Looking good! Left a few comments inline.
src/submodules/googletest
Outdated
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.
You'll want to revert the changes in this submodule before we're able to merge this.
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.
@captainsafia
done
[InlineData("""app.MapGet("/", ([FromHeader(Name = "q")] string[]? arr) => arr);""", "", "[]")] | ||
[InlineData("""app.MapGet("/", ([FromHeader(Name = "q")] string[]? arr) => arr);""", "a,b,c", "[\"a\",\"b\",\"c\"]")] | ||
[InlineData("""app.MapGet("/", ([FromHeader(Name = "q")] int[]? arr) => arr);""", "1,2,3", "[1,2,3]")] | ||
public async Task RequestDelegateGenerator_FromHeader_CommaSeparatedValues(string source, string headerContent, string expectedBody) |
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.
If you move this test case to RequestDelegateCreationTests.Arrays.cs
we'll get coverage for both compile-time and run-time code gen with a single test case.
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.
@captainsafia
moved
@@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Http.Generated | |||
{ | |||
var wasParamCheckFailure = false; | |||
// Endpoint Parameter: p (Type = Microsoft.AspNetCore.Http.Generators.Tests.ParsableTodo[], IsOptional = False, IsParsable = True, IsArray = True, Source = Header) | |||
var p_raw = httpContext.Request.Headers["p"]; | |||
var p_raw = httpContext.Request.Headers.GetCommaSeparatedValues("p"); |
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.
Nice use of the extension method here!
BindParameterFromValue(parameter, GetValueFromProperty(property, itemProperty, key, GetExpressionType(parameter.ParameterType)), factoryContext, source); | ||
private static Expression BindParameterFromProperty(ParameterInfo parameter, MemberExpression property, PropertyInfo itemProperty, string key, RequestDelegateFactoryContext factoryContext, string source) | ||
{ | ||
var expressionType = GetExpressionType(parameter.ParameterType); |
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.
Are string arrays the only type that we need to handle here? Does MVC support serializing int[]
from the header for example?
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.
Fixed
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.
Looks good overall! Left one small comment inline that we can use as a way to rekick the stale build for this change.
{ | ||
var valueExpression = (source == "header" && parameter.ParameterType.IsArray) | ||
? Expression.Call( | ||
typeof(ParsingHelpers).GetMethod(nameof(ParsingHelpers.GetHeaderSplit), BindingFlags.Public | BindingFlags.Static, [typeof(IHeaderDictionary), typeof(string)])!, |
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: consider caching this at the top of the file as the other MethodInfo
definitions.
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 will do this in February.
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.
MethodInfo
caching done
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.
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Fix for: Minimal APIs and controllers treat header arrays differently #54978
Alter BindParameterFromProperty(...) method
Description
The root cause of the issue is in
GetValueFromProperty(...)
behavior - it returns an Expression that evaluateshttpContext.Request.Headers[key]
. What we want, is to callhttpContext.Request.Headers.GetCommaSeparatedValues(key)
when the source is "header" and [FromHeader] is attached to an array.GetCommaSeparatedValues(key) is an extension method, implemented as ParsingHelpers.GetHeaderSplit(IHeaderDictionary, string)
Fixes #54978