Skip to content

Decimal type comma separator #4

Description

@oleg-glushko

My regional settings use a comma symbol as a decimal number separator. It doesn't work with the default validator, so I had to adapt your example and redefine the jQuery Validation rule.

public class DecimalBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        var modelType = context.Metadata.UnderlyingOrModelType;
        if (modelType == typeof(decimal) || modelType == typeof(decimal?))
            return new BinderTypeModelBinder(typeof(DecimalBinder));

        return null;
    }
}

public class DecimalBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueResult == ValueProviderResult.None)
            return Task.CompletedTask;

        decimal result;

        if (valueResult.FirstValue != string.Empty)
        {
            // try current culture
            if (!decimal.TryParse(valueResult.FirstValue, System.Globalization.NumberStyles.Any, CultureInfo.CurrentCulture, out result) &&
                    // then try in US culture
                    !decimal.TryParse(valueResult.FirstValue, System.Globalization.NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result) &&
                    // finally try neutral culture
                    !decimal.TryParse(valueResult.FirstValue, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out result))
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "You should provide a valid decimal value");
                return Task.CompletedTask;
            }

            bindingContext.Result = ModelBindingResult.Success(result);
        }
        else if (!bindingContext.ModelMetadata.IsNullableValueType)
        {
            bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "Decimal value is non-nullable and can't be empty");
        }

        return Task.CompletedTask;
    }
}

builder.Services.AddRazorPages().AddViewOptions(options =>
{
    options.ModelBinderProviders.Insert(0, new DecimalBinderProvider());
});

Put the below code into the "/wwwroot/js/number-validator-override.js" and link it in "_ValidationScriptsPartial.cshtml" after the <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> line.

$.validator.methods.number = function (value, element) {
    return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[\s\.,]\d{3})+)(?:[\.,]\d+)?$/.test(value);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions