From 99407d139615530a0c3a9248547e96b61ec254b1 Mon Sep 17 00:00:00 2001 From: StickFun <2000stickfun@gmail.com> Date: Sat, 2 Aug 2025 23:46:53 +0400 Subject: [PATCH 1/3] Added string arrays to simple binding --- src/Http/Http.Extensions/src/RequestDelegateFactory.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index aaebe4179806..496e078c5824 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -129,6 +129,7 @@ public static partial class RequestDelegateFactory private static readonly string[] FormFileContentType = new[] { "multipart/form-data" }; private static readonly string[] FormContentType = new[] { "multipart/form-data", "application/x-www-form-urlencoded" }; private static readonly string[] PlaintextContentType = new[] { "text/plain" }; + private static readonly Type[] StringTypes = new[] {typeof(string), typeof(StringValues), typeof(StringValues?) }; /// /// Returns metadata inferred automatically for the created by . @@ -791,11 +792,11 @@ private static Expression CreateArgument(ParameterInfo parameter, RequestDelegat // For complex types, leverage the shared form binding infrastructure. For example, // shared form binding does not currently only supports types that implement IParsable // while RDF's binding implementation supports all TryParse implementations. - var useSimpleBinding = parameter.ParameterType == typeof(string) || - parameter.ParameterType == typeof(StringValues) || - parameter.ParameterType == typeof(StringValues?) || + var useSimpleBinding = StringTypes.Contains(parameter.ParameterType) || ParameterBindingMethodCache.Instance.HasTryParseMethod(parameter.ParameterType) || - (parameter.ParameterType.IsArray && ParameterBindingMethodCache.Instance.HasTryParseMethod(parameter.ParameterType.GetElementType()!)); + (parameter.ParameterType.IsArray && + (StringTypes.Contains(parameter.ParameterType.GetElementType()) || + ParameterBindingMethodCache.Instance.HasTryParseMethod(parameter.ParameterType.GetElementType()!))); hasTryParse = useSimpleBinding; return useSimpleBinding ? BindParameterFromFormItem(parameter, formAttribute.Name ?? parameter.Name, factoryContext) From 8517ce45050aeb3a51625139c58de88d852c0986 Mon Sep 17 00:00:00 2001 From: StickFun <2000stickfun@gmail.com> Date: Sun, 3 Aug 2025 16:42:29 +0400 Subject: [PATCH 2/3] Added unit test for handling string array from form parameter --- .../test/RequestDelegateFactoryTests.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index 7cee04fb8a0f..c83decee4dcc 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -684,6 +684,30 @@ public async Task RequestDelegateHandlesNullableStringValuesFromExplicitQueryStr Assert.Null(httpContext.Items["form"]); } + [Fact] + public async Task RequestDelegateHandlesFromFormStringArrayParameter() + { + var httpContext = CreateHttpContext(); + httpContext.Request.Form = new FormCollection(null); + + var factoryResult = RequestDelegateFactory.Create( + (HttpContext context, [FromForm(Name = "form")] string[] formValues) => + { + context.Items["form"] = formValues; + }); + + var requestDelegate = factoryResult.RequestDelegate; + + await requestDelegate(httpContext); + + var parameterBindingMetadata = factoryResult.EndpointMetadata + .FirstOrDefault(e => e is ParameterBindingMetadata metadata && + metadata.Name == "formValues") as ParameterBindingMetadata; + + Assert.NotNull(parameterBindingMetadata); + Assert.Equal(typeof(string[]), parameterBindingMetadata.ParameterInfo.ParameterType); + } + [Fact] public async Task RequestDelegateCanAwaitValueTasksThatAreNotImmediatelyCompleted() { From 8f28e1daafaea2c7b8c92f007c06291c2ab434bf Mon Sep 17 00:00:00 2001 From: StickFun <2000stickfun@gmail.com> Date: Tue, 5 Aug 2025 20:25:37 +0400 Subject: [PATCH 3/3] Updated test with HttpContext check --- .../test/RequestDelegateFactoryTests.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index c83decee4dcc..4a82c4821c25 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -688,7 +688,10 @@ public async Task RequestDelegateHandlesNullableStringValuesFromExplicitQueryStr public async Task RequestDelegateHandlesFromFormStringArrayParameter() { var httpContext = CreateHttpContext(); - httpContext.Request.Form = new FormCollection(null); + httpContext.Request.Form = new FormCollection(new Dictionary + { + ["form"] = new(new[] { "1", "2", "3" }) + }); var factoryResult = RequestDelegateFactory.Create( (HttpContext context, [FromForm(Name = "form")] string[] formValues) => @@ -700,12 +703,7 @@ public async Task RequestDelegateHandlesFromFormStringArrayParameter() await requestDelegate(httpContext); - var parameterBindingMetadata = factoryResult.EndpointMetadata - .FirstOrDefault(e => e is ParameterBindingMetadata metadata && - metadata.Name == "formValues") as ParameterBindingMetadata; - - Assert.NotNull(parameterBindingMetadata); - Assert.Equal(typeof(string[]), parameterBindingMetadata.ParameterInfo.ParameterType); + Assert.Equal(new StringValues(new[] { "1", "2", "3" }), httpContext.Items["form"]!); } [Fact]