Updated the core of Mvc.ModelBinding.MultiParameter

alphons <alphons@heijden.com> 24 Nov 2024, 16:15
fe6c614e95822d1e4ed3043634c2535a37ef4635
14 files changed
  • src/Mvc.ModelBinding.MultiParameter.Testing/Controllers/ComplexController.cs
  • src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/SpeedTest.js
  • src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/Ui.css
  • src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/index.html
  • src/Mvc.ModelBinding.MultiParameter/BindingSourceValueProvider.cs
  • src/Mvc.ModelBinding.MultiParameter/CookyValueProviderFactory.cs
  • src/Mvc.ModelBinding.MultiParameter/FormValueProviderFactory.cs
  • src/Mvc.ModelBinding.MultiParameter/GenericModelBinderProvider.cs
  • src/Mvc.ModelBinding.MultiParameter/GenericValueProvider.cs
  • src/Mvc.ModelBinding.MultiParameter/HeaderValueProviderFactory.cs
  • src/Mvc.ModelBinding.MultiParameter/Helper.cs
  • src/Mvc.ModelBinding.MultiParameter/JsonValueProviderFactory.cs
  • src/Mvc.ModelBinding.MultiParameter/QueryStringValueProviderFactory.cs
  • src/Mvc.ModelBinding.MultiParameter/RouteValueProviderFactory.cs
diff --git a/src/Mvc.ModelBinding.MultiParameter.Testing/Controllers/ComplexController.cs b/src/Mvc.ModelBinding.MultiParameter.Testing/Controllers/ComplexController.cs
index 58fb53c..78d2268 100644
--- a/src/Mvc.ModelBinding.MultiParameter.Testing/Controllers/ComplexController.cs
+++ b/src/Mvc.ModelBinding.MultiParameter.Testing/Controllers/ComplexController.cs
@@ -579,9 +579,8 @@ public class ApiController : ControllerBase
/// <param name="mycookie">the name of the var must the name of the cookie</param>
/// <returns></returns>
[HttpGet("~/api/GetCookie")]
- public async Task<IActionResult> GetCookie(string mycookie)
+ public IActionResult GetCookie(string mycookie)
{
- await Task.Yield();
return Ok(new
{
Value = mycookie
diff --git a/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/SpeedTest.js b/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/SpeedTest.js
index 8a3433e..8071090 100644
--- a/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/SpeedTest.js
+++ b/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/SpeedTest.js
@@ -43,7 +43,7 @@ async function SpeedTest()
{
output.innerText = '';
- const tasks = Array.from({ length: 50 }, () => MultiBinderTest());
+ const tasks = Array.from({ length: 4 }, () => MultiBinderTest());
await Promise.all(tasks);
console.log("All tasks completed");
}
diff --git a/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/Ui.css b/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/Ui.css
index 98a8d8e..4c5c3e5 100644
--- a/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/Ui.css
+++ b/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/Ui.css
@@ -33,6 +33,7 @@ body
font-weight: 700;
padding: 0.7em 1.0em;
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
+ min-width:150px;
}
.ui-btn:hover
@@ -107,10 +108,9 @@ input, select
input[type="file"]::-webkit-file-upload-button
{
- width: 0;
+ width:0;
padding-left: 0px;
padding-right: 0px;
- padding-top: 0.4em;
border: none;
}
diff --git a/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/index.html b/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/index.html
index 320bd42..a6f32ec 100644
--- a/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/index.html
+++ b/src/Mvc.ModelBinding.MultiParameter.Testing/wwwroot/index.html
@@ -31,6 +31,6 @@
<div><span id="PostIt" class="ui-btn">PostIt</span></div>
- <p><a href="speedtest.html">SpeedTest</a></p>
+ <div><a href="speedtest.html" class="ui-btn">SpeedTest</a></div>
</body>
</html>
diff --git a/src/Mvc.ModelBinding.MultiParameter/BindingSourceValueProvider.cs b/src/Mvc.ModelBinding.MultiParameter/BindingSourceValueProvider.cs
index 54067ef..5e43e30 100644
--- a/src/Mvc.ModelBinding.MultiParameter/BindingSourceValueProvider.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/BindingSourceValueProvider.cs
@@ -9,12 +9,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
public abstract class BindingSourceValueProvider : IBindingSourceValueProvider
{
/// <summary>
- /// Creates a new <see cref="BindingGetModelProvider"/>.
+ /// Initializes a new instance of the <see cref="BindingSourceValueProvider"/> class.
/// </summary>
/// <param name="bindingSource">
- /// The <see cref="ModelBinding.BindingSource"/>. Must be a single-source (non-composite) with
- /// <see cref="BindingSource.IsGreedy"/> equal to <c>false</c>.
+ /// The <see cref="BindingSource"/> associated with this provider.
+ /// Must be a single-source (non-composite) with <see cref="BindingSource.IsGreedy"/> set to <c>false</c>.
/// </param>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="bindingSource"/> is null.</exception>
public BindingSourceValueProvider(BindingSource bindingSource)
{
ArgumentNullException.ThrowIfNull(bindingSource);
@@ -41,10 +42,7 @@ public abstract class BindingSourceValueProvider : IBindingSourceValueProvider
{
ArgumentNullException.ThrowIfNull(bindingSource);
- if (bindingSource.CanAcceptDataFrom(BindingSource))
- return this;
- else
- return null;
+ return bindingSource.CanAcceptDataFrom(BindingSource) ? this : null;
}
public virtual object? GetModel(string key, Type t)
diff --git a/src/Mvc.ModelBinding.MultiParameter/CookyValueProviderFactory.cs b/src/Mvc.ModelBinding.MultiParameter/CookyValueProviderFactory.cs
index 7847074..fda8d3e 100644
--- a/src/Mvc.ModelBinding.MultiParameter/CookyValueProviderFactory.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/CookyValueProviderFactory.cs
@@ -4,51 +4,27 @@
// Version: 1.2 Date: 2022-04-10
// Version: 1.3 Date: 2024-11-23
-using Mvc.ModelBinding.MultiParameter;
using System.Text.Json;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
-public class CookyValueProviderFactory : IValueProviderFactory
+public class CookyValueProviderFactory(JsonSerializerOptions? jsonSerializerOptions) : IValueProviderFactory
{
- private readonly JsonSerializerOptions? jsonSerializerOptions;
- public CookyValueProviderFactory(JsonSerializerOptions? Options)
+ public Task CreateValueProviderAsync(ValueProviderFactoryContext? context)
{
- this.jsonSerializerOptions = Options;
- }
- public CookyValueProviderFactory()
- {
- this.jsonSerializerOptions = null;
- }
+ if (context?.ActionContext?.HttpContext?.Request?.Cookies is { Count: > 0 } cookies)
+ {
+ var jsonString = JsonSerializer.Serialize(
+ cookies.ToDictionary(c => c.Key, c => c.Value),
+ jsonSerializerOptions);
+ var jsonDocument = JsonDocument.Parse(jsonString);
- public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
- {
- ArgumentNullException.ThrowIfNull(context);
- var cookies = context.ActionContext.HttpContext.Request.Cookies;
- if (cookies != null && cookies.Count > 0)
- {
- try
- {
- var cookieList = cookies
- .Select(cookie => $"\"{Helper.EscapeForJson(cookie.Key)}\": \"{Helper.EscapeForJson(cookie.Value)}\"")
- .ToArray();
-
- var json = $"{{{string.Join(',', cookieList)}}}";
- var jsonDocument = JsonDocument.Parse(json, options: default);
-
- var valueProvider = new GenericValueProvider(
- BindingSource.Special,
- jsonDocument,
- null,
- jsonSerializerOptions);
-
- context.ValueProviders.Add(valueProvider);
- }
- catch (Exception ex)
- {
- Console.Error.WriteLine($"[CookyValueProvider] Error parsing cookies: {ex.Message}");
- }
+ context.ValueProviders.Add(new GenericValueProvider(
+ BindingSource.Special,
+ jsonDocument: jsonDocument,
+ formCollection: null,
+ jsonSerializerOptions: jsonSerializerOptions));
}
return Task.CompletedTask;
}
diff --git a/src/Mvc.ModelBinding.MultiParameter/FormValueProviderFactory.cs b/src/Mvc.ModelBinding.MultiParameter/FormValueProviderFactory.cs
index f531739..2f54a64 100644
--- a/src/Mvc.ModelBinding.MultiParameter/FormValueProviderFactory.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/FormValueProviderFactory.cs
@@ -16,26 +16,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
/// <summary>
/// A <see cref="IValueProviderFactory"/> for <see cref="GenericValueProvider"/>.
/// </summary>
-public class FormValueProviderFactory : IValueProviderFactory
+public class FormValueProviderFactory(JsonSerializerOptions? jsonSerializerOptions) : IValueProviderFactory
{
- private readonly JsonSerializerOptions? jsonSerializerOptions;
-
- public FormValueProviderFactory(JsonSerializerOptions? Options) : base()
- {
- this.jsonSerializerOptions = Options;
- }
- public FormValueProviderFactory()
- {
- this.jsonSerializerOptions = null;
- }
-
/// <inheritdoc />
- public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
+ public Task CreateValueProviderAsync(ValueProviderFactoryContext? context)
{
- ArgumentNullException.ThrowIfNull(context);
-
- var request = context.ActionContext.HttpContext.Request;
- if (request.HasFormContentType)
+ if (context?.ActionContext?.HttpContext?.Request is { HasFormContentType: true })
{
// Allocating a Task only when the body is form data.
return AddValueProviderAsync(context);
@@ -47,32 +33,27 @@ public class FormValueProviderFactory : IValueProviderFactory
private async Task AddValueProviderAsync(ValueProviderFactoryContext context)
{
var request = context.ActionContext.HttpContext.Request;
- IFormCollection form;
+
+ IFormCollection formCollection;
try
{
- form = await request.ReadFormAsync();
+ formCollection = await request.ReadFormAsync();
}
catch (InvalidDataException ex)
{
- // ReadFormAsync can throw InvalidDataException if the form content is malformed.
- // Wrap it in a ValueProviderException that the CompositeValueProvider special cases.
- throw new ValueProviderException(ex.Message, ex);
+ throw new ValueProviderException("Malformed form content detected.", ex);
}
catch (IOException ex)
{
- // ReadFormAsync can throw IOException if the client disconnects.
- // Wrap it in a ValueProviderException that the CompositeValueProvider special cases.
- throw new ValueProviderException(ex.Message, ex);
+ throw new ValueProviderException("Client disconnected during form reading.", ex);
}
- var valueProvider = new GenericValueProvider(
+ context.ValueProviders.Add(new GenericValueProvider(
BindingSource.Form,
- null,
- form,
- this.jsonSerializerOptions);
-
- context.ValueProviders.Add(valueProvider);
+ jsonDocument: null,
+ formCollection: formCollection,
+ jsonSerializerOptions: jsonSerializerOptions));
}
}
diff --git a/src/Mvc.ModelBinding.MultiParameter/GenericModelBinderProvider.cs b/src/Mvc.ModelBinding.MultiParameter/GenericModelBinderProvider.cs
index 4f60a03..e332121 100644
--- a/src/Mvc.ModelBinding.MultiParameter/GenericModelBinderProvider.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/GenericModelBinderProvider.cs
@@ -25,7 +25,7 @@ public class GenericModelBinder : IModelBinder
this.type = type ?? throw new ArgumentNullException(nameof(type));
}
- public Task BindModelAsync(ModelBindingContext bindingContext)
+ public Task BindModelAsync(ModelBindingContext? bindingContext)
{
ArgumentNullException.ThrowIfNull(bindingContext);
@@ -88,7 +88,7 @@ public class GenericModelBinder : IModelBinder
/// </summary>
public class GenericModelBinderProvider : IModelBinderProvider
{
- public IModelBinder? GetBinder(ModelBinderProviderContext context)
+ public IModelBinder? GetBinder(ModelBinderProviderContext? context)
{
ArgumentNullException.ThrowIfNull(context);
diff --git a/src/Mvc.ModelBinding.MultiParameter/GenericValueProvider.cs b/src/Mvc.ModelBinding.MultiParameter/GenericValueProvider.cs
index bb3b5af..76e6948 100644
--- a/src/Mvc.ModelBinding.MultiParameter/GenericValueProvider.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/GenericValueProvider.cs
@@ -14,8 +14,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
public class GenericValueProvider(
BindingSource bindingSource,
JsonDocument? jsonDocument,
- IFormCollection? form,
- JsonSerializerOptions? options) : BindingSourceValueProvider(bindingSource)
+ IFormCollection? formCollection,
+ JsonSerializerOptions? jsonSerializerOptions) : BindingSourceValueProvider(bindingSource)
{
public override bool ContainsPrefix(string prefix)
{
@@ -26,13 +26,13 @@ public class GenericValueProvider(
jsonDocument.RootElement.TryGetProperty(prefix, out _))
return true;
- if (form != null)
+ if (formCollection != null)
{
- if (form.ContainsKey(prefix))
+ if (formCollection.ContainsKey(prefix))
return true;
- if (form.Files != null &&
- form.Files.Any(x => x.Name == prefix))
+ if (formCollection.Files != null &&
+ formCollection.Files.Any(x => x.Name == prefix))
return true;
}
@@ -62,29 +62,29 @@ public class GenericValueProvider(
}
else if (prop.ValueKind != JsonValueKind.Array || t.IsArray || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>)))
{
- return prop.Deserialize(t, options);
+ return prop.Deserialize(t, jsonSerializerOptions);
}
else
{
var first = prop.EnumerateArray().FirstOrDefault();
if (first.ValueKind != JsonValueKind.Null)
- return first.Deserialize(t, options);
+ return first.Deserialize(t, jsonSerializerOptions);
}
}
- if (form != null)
+ if (formCollection != null)
{
- if (form.ContainsKey(key))
+ if (formCollection.ContainsKey(key))
{
var model = TypeDescriptor.GetConverter(t).ConvertFrom(
context: null,
culture: System.Globalization.CultureInfo.InvariantCulture,
- value: form[key].FirstOrDefault() ?? new object()); // Needs some tweaking
+ value: formCollection[key].FirstOrDefault() ?? new object()); // Needs some tweaking
return model;
}
- if (form.Files != null && t == typeof(IFormFile))
- return form.Files.FirstOrDefault(x => x.Name == key);
+ if (formCollection.Files != null && t == typeof(IFormFile))
+ return formCollection.Files.FirstOrDefault(x => x.Name == key);
}
return null;
}
diff --git a/src/Mvc.ModelBinding.MultiParameter/HeaderValueProviderFactory.cs b/src/Mvc.ModelBinding.MultiParameter/HeaderValueProviderFactory.cs
index b36eeff..6c2bc58 100644
--- a/src/Mvc.ModelBinding.MultiParameter/HeaderValueProviderFactory.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/HeaderValueProviderFactory.cs
@@ -9,35 +9,21 @@ using System.Text.Json;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
-public class HeaderValueProviderFactory : IValueProviderFactory
+public class HeaderValueProviderFactory(JsonSerializerOptions? jsonSerializerOptions) : IValueProviderFactory
{
- private readonly JsonSerializerOptions? jsonSerializerOptions;
- public HeaderValueProviderFactory(JsonSerializerOptions? Options)
+ public Task CreateValueProviderAsync(ValueProviderFactoryContext? context)
{
- this.jsonSerializerOptions = Options;
- }
- public HeaderValueProviderFactory()
- {
- this.jsonSerializerOptions = null;
- }
- public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
- {
- ArgumentNullException.ThrowIfNull(context);
-
- var headers = context.ActionContext.HttpContext.Request.Headers;
- if (headers != null && headers.Count > 0)
+ if (context?.ActionContext?.HttpContext?.Request?.Headers is { Count: > 0 } headers)
{
- var json = JsonSerializer.Serialize(headers);
+ var json = JsonSerializer.Serialize(headers, jsonSerializerOptions);
- var jsonDocument = JsonDocument.Parse(json, options: default);
+ var jsonDocument = JsonDocument.Parse(json);
- var valueProvider = new GenericValueProvider(
+ context.ValueProviders.Add(new GenericValueProvider(
BindingSource.Header,
- jsonDocument,
- null,
- jsonSerializerOptions);
-
- context.ValueProviders.Add(valueProvider);
+ jsonDocument: jsonDocument,
+ formCollection: null,
+ jsonSerializerOptions: jsonSerializerOptions));
}
return Task.CompletedTask;
diff --git a/src/Mvc.ModelBinding.MultiParameter/Helper.cs b/src/Mvc.ModelBinding.MultiParameter/Helper.cs
deleted file mode 100644
index 24c0d3d..0000000
--- a/src/Mvc.ModelBinding.MultiParameter/Helper.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Text.RegularExpressions;
-
-namespace Mvc.ModelBinding.MultiParameter;
-
-internal partial class Helper
-{
- [GeneratedRegex("[\"\\\\\b\f\n\r\t]")]
- private static partial Regex MyRegex();
- public static string EscapeForJson(string? value)
- {
- if (string.IsNullOrEmpty(value))
- return string.Empty;
-
- return MyRegex().Replace(value, match =>
- {
- return match.Value switch
- {
- "\"" => "\\\"",
- "\\" => "\\\\",
- "\b" => "\\b",
- "\f" => "\\f",
- "\n" => "\\n",
- "\r" => "\\r",
- "\t" => "\\t",
- _ => match.Value
- };
- });
- }
-}
diff --git a/src/Mvc.ModelBinding.MultiParameter/JsonValueProviderFactory.cs b/src/Mvc.ModelBinding.MultiParameter/JsonValueProviderFactory.cs
index d6b8f0e..84bcd33 100644
--- a/src/Mvc.ModelBinding.MultiParameter/JsonValueProviderFactory.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/JsonValueProviderFactory.cs
@@ -8,35 +8,20 @@ using System.Text.Json;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
-public class JsonValueProviderFactory : IValueProviderFactory
+public class JsonValueProviderFactory(JsonSerializerOptions? jsonSerializerOptions) : IValueProviderFactory
{
- private readonly JsonSerializerOptions? jsonSerializerOptions;
- public JsonValueProviderFactory(JsonSerializerOptions? Options)
+ public Task CreateValueProviderAsync(ValueProviderFactoryContext? context)
{
- this.jsonSerializerOptions = Options;
- }
- public JsonValueProviderFactory()
- {
- this.jsonSerializerOptions = null;
- }
- public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
- {
- ArgumentNullException.ThrowIfNull(context);
-
- var request = context.ActionContext.HttpContext.Request;
-
- if (request.Method == "POST")
+ if (context?.ActionContext?.HttpContext?.Request is { Method: "POST" } request)
{
- if (request.ContentType == null || request.ContentType.StartsWith("application/json"))
+ if ((request.ContentType == null ||
+ request.ContentType.StartsWith("application/json"))
+ && (request.ContentLength == null ||
+ request.ContentLength >= 2)) // matches an empty "{}" post
{
- if (request.ContentLength == null || // Chunked encoding
- request.ContentLength >= 2) // Normal encoding, using content length minimum '{}'
- {
- return AddValueProviderAsync(context);
- }
+ return AddValueProviderAsync(context);
}
}
-
return Task.CompletedTask;
}
@@ -60,12 +45,10 @@ public class JsonValueProviderFactory : IValueProviderFactory
throw new ValueProviderException(ex.Message, ex);
}
- var valueProvider = new GenericValueProvider(
+ context.ValueProviders.Add(new GenericValueProvider(
BindingSource.Body,
- jsonDocument,
- null,
- jsonSerializerOptions);
-
- context.ValueProviders.Add(valueProvider);
+ jsonDocument: jsonDocument,
+ formCollection: null,
+ jsonSerializerOptions: jsonSerializerOptions));
}
}
diff --git a/src/Mvc.ModelBinding.MultiParameter/QueryStringValueProviderFactory.cs b/src/Mvc.ModelBinding.MultiParameter/QueryStringValueProviderFactory.cs
index 5b77e26..8d84db1 100644
--- a/src/Mvc.ModelBinding.MultiParameter/QueryStringValueProviderFactory.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/QueryStringValueProviderFactory.cs
@@ -7,8 +7,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using Mvc.ModelBinding.MultiParameter;
-using System.Net;
using System.Text.Json;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
@@ -18,40 +16,31 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
/// A <see cref="IValueProviderFactory"/> that creates <see cref="GenericValueProvider"/> instances that
/// read values from the request query-string.
/// </summary>
-public class QueryStringValueProviderFactory : IValueProviderFactory
+public class QueryStringValueProviderFactory(JsonSerializerOptions? jsonSerializerOptions) : IValueProviderFactory
{
- private readonly JsonSerializerOptions? jsonSerializerOptions;
- public QueryStringValueProviderFactory(JsonSerializerOptions? Options) : base()
- {
- this.jsonSerializerOptions = Options;
- }
-
- public QueryStringValueProviderFactory()
- {
- this.jsonSerializerOptions = null;
- }
-
/// <inheritdoc />
- public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
+ public Task CreateValueProviderAsync(ValueProviderFactoryContext? context)
{
- ArgumentNullException.ThrowIfNull(context);
-
- var query = context.ActionContext.HttpContext.Request.Query;
- if (query != null && query.Count > 0)
+ if (context?.ActionContext?.HttpContext?.Request?.Query is { Count: > 0 } query)
{
- var list = query
- .Select(x => $"\"{Helper.EscapeForJson(x.Key)}\": \"{Helper.EscapeForJson(x.Value)}\"")
- .ToArray();
- var json = $"{{{string.Join(',', list)}}}";
- var jsonDocument = JsonDocument.Parse(json, options: default);
+ var queryDictionary = query.ToDictionary(
+ pair => pair.Key,
+ pair => pair.Value.Count > 1
+ ? pair.Value.ToArray() // Convert multiple values to an array
+ : (object)pair.Value.ToString()); // Use a string for a single value
+
- var valueProvider = new GenericValueProvider(
+ var jsonDocument = JsonDocument.Parse(
+ JsonSerializer.Serialize(
+ queryDictionary,
+ jsonSerializerOptions));
+
+ context.ValueProviders.Add(new GenericValueProvider(
BindingSource.Query,
jsonDocument,
- null,
- this.jsonSerializerOptions);
-
- context.ValueProviders.Add(valueProvider);
+ formCollection: null,
+ jsonSerializerOptions: jsonSerializerOptions
+ ));
}
return Task.CompletedTask;
diff --git a/src/Mvc.ModelBinding.MultiParameter/RouteValueProviderFactory.cs b/src/Mvc.ModelBinding.MultiParameter/RouteValueProviderFactory.cs
index a6e4e8c..85433f0 100644
--- a/src/Mvc.ModelBinding.MultiParameter/RouteValueProviderFactory.cs
+++ b/src/Mvc.ModelBinding.MultiParameter/RouteValueProviderFactory.cs
@@ -11,40 +11,27 @@ using System.Text.Json;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.MultiParameter;
-
/// <summary>
/// A <see cref="IValueProviderFactory"/> for creating <see cref="GenericValueProvider"/> instances.
/// </summary>
-public class RouteValueProviderFactory : IValueProviderFactory
+public class RouteValueProviderFactory(JsonSerializerOptions? jsonSerializerOptions) : IValueProviderFactory
{
- private readonly JsonSerializerOptions? jsonSerializerOptions;
-
- public RouteValueProviderFactory(JsonSerializerOptions? Options) : base()
- {
- this.jsonSerializerOptions = Options;
- }
- public RouteValueProviderFactory()
- {
- this.jsonSerializerOptions = null;
- }
-
- /// <inheritdoc />
- public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
- {
- ArgumentNullException.ThrowIfNull(context);
-
- var request = context.ActionContext.HttpContext.Request;
- var jsonString = JsonSerializer.Serialize(request.RouteValues);
- var jsonDocument = JsonDocument.Parse(jsonString, options: default);
-
- var valueProvider = new GenericValueProvider(
- BindingSource.Path,
- jsonDocument,
- null,
- this.jsonSerializerOptions);
-
- context.ValueProviders.Add(valueProvider);
-
- return Task.CompletedTask;
- }
+ /// <inheritdoc />
+ public Task CreateValueProviderAsync(ValueProviderFactoryContext? context)
+ {
+ if (context?.ActionContext?.HttpContext?.Request?.RouteValues is { Count: > 0 } routeValues)
+ {
+ var jsonString = JsonSerializer.Serialize(routeValues, jsonSerializerOptions);
+
+ var jsonDocument = JsonDocument.Parse(jsonString);
+
+ context.ValueProviders.Add(new GenericValueProvider(
+ BindingSource.Path,
+ jsonDocument: jsonDocument,
+ formCollection: null,
+ jsonSerializerOptions: jsonSerializerOptions));
+ }
+
+ return Task.CompletedTask;
+ }
}