Search code examples
c#kendo-uikendonumerictextbox

Decimal value set to null in model when posting


I have a Kendo NumericTextbox

 @(Html.Kendo().NumericTextBoxFor(m => m.SomeDecimal)
                                    .Name("SomeDecimal")
                                    .Min(0)
                                    .Max(99999999)
                                    .Decimals(2)
                                  ) 

When posting my form containing this NumericTextbox the value of SomeDecimal is set to null in the model.

Please note: I replaced the Kendo NumericTextbox with a normal textbox and had the same issue because the number that was entered contained a full stop (.) instead of a comma (,). When I replaced the full stop with a comma everything worked as expected.

Do I have to specify a different culture perhaps?


Solution

  • I found a workaround for this problem,

    I created a new class DecimalModelBinder to overwrite the default model binding of decimal fields. The code is below. Here I attempt to convert the decimal value, if the conversion fails I replace all full stops with commas and try to convert again. If the second conversion attempt fails I replace all commas with full stops and try again.

    public class DecimalModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            var modelState = new ModelState {Value = valueResult};
            object actualValue = null;
            try
            {
                // Try to convert the actual number that was recieved.
                actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
            }
            catch
            {
                try
                {
                    // Replace any . with , and try to convert.
                    actualValue = Convert.ToDecimal(valueResult.AttemptedValue.Replace('.',','), CultureInfo.CurrentCulture);
                }
                catch
                {
                    try
                    {
                        // Replace any , with . and try to convert.
                        actualValue = Convert.ToDecimal(valueResult.AttemptedValue.Replace(',', '.'), CultureInfo.CurrentCulture);
                    }
                    catch (Exception ex)
                    {
                        modelState.Errors.Add(ex);                                               
                    }
                }
            }
    
            bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
    
            return actualValue;
        }
    }
    

    You have to add the DecimalModelBinder in your Global.asx file

    protected void Application_Start()
    {
        RouteTable.Routes.MapHubs();
        AreaRegistration.RegisterAllAreas();
    
        ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
        ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
    
        // All other code.
    }