From 40531db1aea0af90777c42275ec1cb55bb587030 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sat, 21 Nov 2020 11:58:35 -0700 Subject: [PATCH] Add NullableEnumModelBinder and NullableEnumModelBinderProvider --- .../ModelBinders/NullableEnumModelBinder.cs | 47 +++++++++++++++++++ .../NullableEnumModelBinderProvider.cs | 27 +++++++++++ .../ApiServiceCollectionExtensions.cs | 3 ++ 3 files changed, 77 insertions(+) create mode 100644 Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs create mode 100644 Jellyfin.Api/ModelBinders/NullableEnumModelBinderProvider.cs diff --git a/Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs b/Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs new file mode 100644 index 000000000..5d296227e --- /dev/null +++ b/Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs @@ -0,0 +1,47 @@ +using System; +using System.ComponentModel; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Api.ModelBinders +{ + /// + /// Nullable enum model binder. + /// + public class NullableEnumModelBinder : IModelBinder + { + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + public NullableEnumModelBinder(ILogger logger) + { + _logger = logger; + } + + /// + 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 != 0) + { + try + { + var convertedValue = converter.ConvertFromString(valueProviderResult.FirstValue); + bindingContext.Result = ModelBindingResult.Success(convertedValue); + } + catch (FormatException e) + { + _logger.LogWarning(e, "Error converting value."); + } + } + + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Jellyfin.Api/ModelBinders/NullableEnumModelBinderProvider.cs b/Jellyfin.Api/ModelBinders/NullableEnumModelBinderProvider.cs new file mode 100644 index 000000000..bc12ad05d --- /dev/null +++ b/Jellyfin.Api/ModelBinders/NullableEnumModelBinderProvider.cs @@ -0,0 +1,27 @@ +using System; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Api.ModelBinders +{ + /// + /// Nullable enum model binder provider. + /// + public class NullableEnumModelBinderProvider : IModelBinderProvider + { + /// + public IModelBinder? GetBinder(ModelBinderProviderContext context) + { + var nullableType = Nullable.GetUnderlyingType(context.Metadata.ModelType); + if (nullableType == null || !nullableType.IsEnum) + { + // Type isn't nullable or isn't an enum. + return null; + } + + var logger = context.Services.GetRequiredService>(); + return new NullableEnumModelBinder(logger); + } + } +} \ No newline at end of file diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index cc98955df..6cb88c9f7 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -17,6 +17,7 @@ using Jellyfin.Api.Auth.LocalAccessPolicy; using Jellyfin.Api.Auth.RequiresElevationPolicy; using Jellyfin.Api.Constants; using Jellyfin.Api.Controllers; +using Jellyfin.Api.ModelBinders; using Jellyfin.Server.Configuration; using Jellyfin.Server.Filters; using Jellyfin.Server.Formatters; @@ -169,6 +170,8 @@ namespace Jellyfin.Server.Extensions opts.OutputFormatters.Add(new CssOutputFormatter()); opts.OutputFormatters.Add(new XmlOutputFormatter()); + + opts.ModelBinderProviders.Insert(0, new NullableEnumModelBinderProvider()); }) // Clear app parts to avoid other assemblies being picked up