Webiant Logo Webiant Logo
  1. No results found.

    Try your search with a different keyword or use * as a wildcard.

InvariantNumberModelBinder.cs

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
}