Fix for: Minimal APIs and controllers treat header arrays differently - #58251
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 |
captainsafia
left a comment
There was a problem hiding this comment.
Looking good! Left a few comments inline.
There was a problem hiding this comment.
You'll want to revert the changes in this submodule before we're able to merge this.
| [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.
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.
| 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.
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.
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.
Fixed
captainsafia
left a comment
There was a problem hiding this comment.
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.
Nit: consider caching this at the top of the file as the other MethodInfo definitions.
There was a problem hiding this comment.
I will do this in February.
There was a problem hiding this comment.
MethodInfo caching done
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