0

I'm developing an ASP .NET MVC 5 application in Visual Studio 2015. I have a simple model created:

public class Article
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Code { get; set; }

    public string Description { get; set; }

    public decimal Price { get; set; }

}

and standard, Visual Studio-added controller and a view. Of course I have a problem with Price decimal field. While trying to add/edit an existing Article, when I type decimal as for instance 5,45 I got an validation error The field Price must be a number.. If I type it as 5.45 I don't get this error, however after submitting the form in my controller Price property of the Article is set to 0 all the time. I explored the web and forums and according to this post's answer created the model binder for decimals as:

public class DecimalModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        return valueProviderResult == null ? base.BindModel(controllerContext, bindingContext) : Convert.ToDecimal(valueProviderResult.AttemptedValue);

    }
}

and then in my Global.asax.cs file I put two lines to add this binder for decimals:

protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        FluentValidationModelValidatorProvider.Configure();

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

However, I still have the same issues, nothing changed.

I also tried to enforce the culture of my PC by putting the following snippet into my Web.config file (as advised in this tutorial):

<system.web>
<globalization culture ="en-US" />
<!--elements removed for clarity-->

but it's all the time the same issue :(. Can you please help me with that? I suppose I'm missing something, but I followed all possible solutions 10 times already and it's still the same...

Thank you in advance!

Community
  • 1
  • 1
Dawid Sibiński
  • 1,657
  • 3
  • 21
  • 40
  • Make sure `bindingContext.ValueProvider.GetValue` it return decimal not integer. – Mehmood Nov 14 '15 at 16:37
  • What is weird it the fact that if I put an breakpoint in my BindModel method in DecimalModelBinder and goes to web page trying to edit or add a new article with Price property filled, this code never gets executed... So I guess there is a problem with adding this Binder to default binders... but I have no idea what could this be. – Dawid Sibiński Nov 14 '15 at 16:41
  • I think you haven't read their answer (from your shared link). "Your value is 3,0 which is not a valid decimal type value. It should be 3.0 replace " comma(,) with dot(.)." – Mehmood Nov 14 '15 at 16:46
  • I wrote that as Price I put "5.45", so the format is OK, it uses dot, not commas, but the value of Price is 0 all the time. – Dawid Sibiński Nov 14 '15 at 16:47
  • then share your code by which you are posting data from view to controller or controller to view. – Mehmood Nov 14 '15 at 16:49
  • Eh, actually you were right! bindingContext.ValueProvider.GetValue provided integers, so I modified it to return decimals and it's OK now :). Thanks a lot! – Dawid Sibiński Nov 14 '15 at 17:11

1 Answers1

3

You should implement IModelBinder:

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 {
            actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
        }
        catch (FormatException e) {
            modelState.Errors.Add(e);
        }

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

Then in your Global.asax.cs:

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
Sirwan Afifi
  • 10,654
  • 14
  • 63
  • 110
  • 1
    Thanks for your answer. However the issue was the same - I just had wrong BindModel method which returned int instead of decimal. But your solution works as well ;). – Dawid Sibiński Nov 14 '15 at 19:58