diff options
| author | Bond-009 <bond.009@outlook.com> | 2025-02-14 04:24:55 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-13 20:24:55 -0700 |
| commit | 2db0750abbcb3994a6d6163652566fe5e0e7c7b7 (patch) | |
| tree | c5783a3b7ef68c09a363569218c8ba850e4d1549 /Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs | |
| parent | fb69b976bf45e44a44b2569cd60dd72b3abeb6b3 (diff) | |
Make the JsonConverters for delimited arrays more generic (#13396)
* Make the JsonConverters for delimited arrays more generic
Also adds some tests for serialization (with different types) as we didn't have any before.
* Ignore warnings
Diffstat (limited to 'Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs')
| -rw-r--r-- | Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs b/Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs new file mode 100644 index 000000000..25b84cbcc --- /dev/null +++ b/Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Api.ModelBinders; + +/// <summary> +/// Comma delimited collection model binder. +/// Returns an empty array of specified type if there is no query parameter. +/// </summary> +public class CommaDelimitedCollectionModelBinder : IModelBinder +{ + private readonly ILogger<CommaDelimitedCollectionModelBinder> _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="CommaDelimitedCollectionModelBinder"/> class. + /// </summary> + /// <param name="logger">Instance of the <see cref="ILogger{CommaDelimitedCollectionModelBinder}"/> interface.</param> + public CommaDelimitedCollectionModelBinder(ILogger<CommaDelimitedCollectionModelBinder> logger) + { + _logger = logger; + } + + /// <inheritdoc/> + public Task BindModelAsync(ModelBindingContext bindingContext) + { + var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + var elementType = bindingContext.ModelType.GetElementType() ?? bindingContext.ModelType.GenericTypeArguments[0]; + var converter = TypeDescriptor.GetConverter(elementType); + + if (valueProviderResult.Length > 1) + { + var typedValues = GetParsedResult(valueProviderResult.Values, elementType, converter); + bindingContext.Result = ModelBindingResult.Success(typedValues); + } + else + { + var value = valueProviderResult.FirstValue; + + if (value is not null) + { + var splitValues = value.Split(',', StringSplitOptions.RemoveEmptyEntries); + var typedValues = GetParsedResult(splitValues, elementType, converter); + bindingContext.Result = ModelBindingResult.Success(typedValues); + } + else + { + var emptyResult = Array.CreateInstance(elementType, 0); + bindingContext.Result = ModelBindingResult.Success(emptyResult); + } + } + + return Task.CompletedTask; + } + + private Array GetParsedResult(IReadOnlyList<string> values, Type elementType, TypeConverter converter) + { + var parsedValues = new object?[values.Count]; + var convertedCount = 0; + for (var i = 0; i < values.Count; i++) + { + try + { + parsedValues[i] = converter.ConvertFromString(values[i].Trim()); + convertedCount++; + } + catch (FormatException e) + { + _logger.LogDebug(e, "Error converting value."); + } + } + + var typedValues = Array.CreateInstance(elementType, convertedCount); + var typedValueIndex = 0; + for (var i = 0; i < parsedValues.Length; i++) + { + if (parsedValues[i] is not null) + { + typedValues.SetValue(parsedValues[i], typedValueIndex); + typedValueIndex++; + } + } + + return typedValues; + } +} |
