3

I have a problem! I am using Mvc5, and I have a property like this.

[DisplayFormat(DataFormatString = "{0:n2}", ApplyFormatInEditMode = true)]
public decimal Total { get; set; }

And razor :

@Html.EditorFor(modelItem => Model.Total, new { htmlAttributes = new { @class = "form-control input-sm" } })

There is not error at this point. But if I send like 1.300,40 I getting always 0.

But if I send like 1300,40 I getting correct value. How can I solve it? I want get correct value, if I send 1300,50 or 1.300,40

Caner
  • 813
  • 1
  • 12
  • 26
  • Can you confirm that `.` is simply formatting for thousands separation, and `,` is decimal separation? – ChadT Apr 29 '17 at 22:52
  • Yes, you're correct – Caner Apr 29 '17 at 22:53
  • I don't want use the when before onsubmit like this function. $(this).val($(this).val().replace(".", "")); ); – Caner Apr 29 '17 at 23:01
  • 1
    Further reading: http://stackoverflow.com/questions/32236013/asp-net-mvc-binding-decimal-value and http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx/. Basically the model binding system does not support formatting thousands separators out of the box. You can apply your own type descriptor and/or model binder to handle this situation. – ChadT Apr 29 '17 at 23:02
  • Thank you very much man! @ChadT – Caner Apr 30 '17 at 07:07

2 Answers2

5

You will have to add your own ModelBinder:

public class DecimalModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        var modelState = new ModelState { Value = valueResult };
        decimal actualValue = 0;

        try
        {
            actualValue = Convert.ToDecimal(valueResult.AttemptedValue,
                CultureInfo.CurrentCulture);
        }
        catch (FormatException e)
        {
            modelState.Errors.Add(e);
        }

        bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
        return actualValue;
    }
}

and register it in your Application_Start:

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());

Reference: http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx/

degant
  • 4,861
  • 1
  • 17
  • 29
0

In case, if we want to have generic ModelBinder for all c# value types then

using System;
using System.Globalization;
using System.Web.Mvc;
public class ValueTypeModelBinder<T> : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        var modelState = new ModelState { Value = valueResult };
        var result = default(T);

        try
        {
            var srcValue = valueResult.AttemptedValue;
            var targetType = typeof(T);

            //Hp --> Logic: Check whether target type is nullable (or) not? 
            //If Yes, Take underlying type for value conversion.
            if (targetType.IsGenericType &&
                targetType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                targetType = Nullable.GetUnderlyingType(targetType);
            }

            if (targetType.IsValueType && (!string.IsNullOrWhiteSpace(srcValue)))
            {
                result = (T)Convert.ChangeType(srcValue, targetType, CultureInfo.CurrentUICulture);
            }
        }
        catch (Exception ex)
        {
            modelState.Errors.Add(ex);
        }

        bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
        return result;
    }
}

After adding the above class, configure ModelBinders under "Application_Start" method in Global.asax.cs file.

using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
public class MvcApplication : HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        ModelBinders.Binders.Add(typeof(decimal?), new ValueTypeModelBinder<decimal?>());
        ModelBinders.Binders.Add(typeof(decimal), new ValueTypeModelBinder<decimal>());
        ModelBinders.Binders.Add(typeof(int), new ValueTypeModelBinder<int>());
        ModelBinders.Binders.Add(typeof(double?), new ValueTypeModelBinder<double?>());
    }
}
hpsanampudi
  • 629
  • 6
  • 9