using System.Globalization; using System.Numerics; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace Nop.Web.Framework.Mvc.ModelBinding.Binders; /// /// Represents model binder for numeric types /// public partial class InvariantNumberModelBinder : IModelBinder { #region Fields protected delegate bool TryParseNumber(string value, NumberStyles styles, IFormatProvider provider, out T result) where T : struct; protected readonly IModelBinder _globalizedBinder; protected readonly NumberStyles _supportedStyles; #endregion #region Ctor public InvariantNumberModelBinder(NumberStyles supportedStyles, IModelBinder globalizedBinder) { ArgumentNullException.ThrowIfNull(globalizedBinder); _globalizedBinder = globalizedBinder; _supportedStyles = supportedStyles; } #endregion #region Utilities protected virtual T? TryParse(string value, TryParseNumber handler) where T : struct { if (!string.IsNullOrWhiteSpace(value) && handler(value, _supportedStyles, CultureInfo.InvariantCulture, out var parseResult)) return parseResult; return null; } #endregion #region Methods /// /// Attempts to bind a model /// /// Model binding context public Task BindModelAsync(ModelBindingContext bindingContext) { ArgumentNullException.ThrowIfNull(bindingContext); var modelName = bindingContext.ModelName; var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); var value = valueProviderResult.FirstValue; if (string.IsNullOrEmpty(value)) return Task.CompletedTask; value = value.Replace('/', '.'); //workaround for a kendonumeric input object model = bindingContext.ModelMetadata.UnderlyingOrModelType switch { Type t when t == typeof(float) => TryParse(value, float.TryParse), Type t when t == typeof(decimal) => TryParse(value, decimal.TryParse), Type t when t == typeof(double) => TryParse(value, double.TryParse), Type t when t == typeof(int) => TryParse(value, int.TryParse), Type t when t == typeof(long) => TryParse(value, long.TryParse), Type t when t == typeof(short) => TryParse(value, short.TryParse), Type t when t == typeof(sbyte) => TryParse(value, sbyte.TryParse), Type t when t == typeof(byte) => TryParse(value, byte.TryParse), Type t when t == typeof(ulong) => TryParse(value, ulong.TryParse), Type t when t == typeof(ushort) => TryParse(value, ushort.TryParse), Type t when t == typeof(uint) => TryParse(value, uint.TryParse), Type t when t == typeof(BigInteger) => TryParse(value, BigInteger.TryParse), _ => null }; if (model is null) return _globalizedBinder.BindModelAsync(bindingContext); //attempt to bind a model depending on the current culture bindingContext.Result = ModelBindingResult.Success(model); return Task.CompletedTask; } #endregion }