19

My problem is that when I try to send a double or decimal via ajax into my C# MVC Controller the value is always null. I can send the value as string and I can send Integers without a problem. Why can't I send values with decimals? When I check the request that is sent from the client the correct value is there (Form Data is price=84.50).

Error:

The parameters dictionary contains a null entry for parameter 'price' of non-nullable type 'System.Decimal'

Html:

 <input type="number" step="1" class="form-control" name="price" id="price">
 <button type="button" class="btn btn-success">Send</button>

Javascript:

$('.btn-success').click(function () {

    //var price = $('#price').val(); - Did not work
    //var price = Number($('#price').val()); Did not work
    var price = Number($('#price').val()).toFixed(2); // Does not work

    $.ajax({
        url: 'PriceFunction',
        type: 'POST',
        data: {
            price: price,
        }
    }).done(function () {

    }).fail(function () {
        console.log("Error in ajaxfunction!");
    });
});

C#:

    [HttpPost]
    public void PriceFunction(decimal price)
    {
     // I have tried with decimal, double and double?.     
    }
Ogglas
  • 62,132
  • 37
  • 328
  • 418

11 Answers11

13

This could be a Culture issue

Be sure that the string you are sending to your action is compliant to the current Culture. (check the decimal number separators . ,)

Exemple

e.g. on a french server, 99.1 will not be understood as 99,1, but will be converted to 0.

Solution

In that case, one solution is to define culture in your Web.Config

  <system.web>
    ...
    <globalization uiCulture="en" culture="en-US"/>
  </system.web>

Or, replacing the separator by the proper one on the client side.

Matthieu Charbonnier
  • 2,794
  • 25
  • 33
12

You need to stringify you data when you are sending decimal values.

data: JSON.stringify({ Price: 5.0 })

This is because the decimal is considered an integer by the default binder.

You could of course change to using the DecimalModelBinder which is detailed at the following link:

ASP.NET MVC3 JSON decimal binding woes

Muhammad Raheel
  • 19,823
  • 7
  • 67
  • 103
Stuart
  • 754
  • 11
  • 25
2

I suggest trying to pass the data as JSON.

data: JSON.stringify({ price: price }),
contentType: "application/json; charset=utf-8"

Just pay attention to include the content type. It may be required in order to the binder know how to parse the data of your request.

1

Try stringifying the JSON passed to the data parameter of the ajax call. That should do the trick.

var data = { price: price };

$.ajax({
    url: 'PriceFunction',
    type: 'POST',
    data: JSON.stringify(data)
}).
Konstantin Dinev
  • 34,219
  • 14
  • 75
  • 100
0

First, using toFixed this way should get you an error since you are trying to use that method on jquery object

use
parseFloat(value).toFixed(2)

Esko
  • 683
  • 9
  • 23
0

Nothing is working in fact but the solution I use it is. You have to send value as a string and convert it into decimal on server side.

So your JS is perfect!

$('.btn-success').click(function () {

    //var price = $('#price').val(); - Did not work
    //var price = Number($('#price').val()); Did not work
    var price = Number($('#price').val()).toFixed(2); // Does not work

    $.ajax({
        url: 'PriceFunction',
        type: 'POST',
        data: {
            price: price,
        }
    }).done(function () {

    }).fail(function () {
        console.log("Error in ajaxfunction!");
    });
});

C#

public readonly CultureInfo ciEN = new CultureInfo("en-US");
 
public async Task<ActionResult> YourMVCMethod(string myDecimalValue)
{
   var message = string.Empty;
   bool result = false;

   try
   {
         decimal convertedValue = Convert.ToDecimal(myDecimalValue, ciEN);
         // process it...                   
                
   }
   catch (Exception ex)
   {
       return Json(new { success = result, msg = ex.Message }, JsonRequestBehavior.AllowGet);
   }

   return Json(new { success = result, msg = message }, JsonRequestBehavior.AllowGet);
}

Web.Config

It contains your global culture!

<globalization uiCulture="your" culture="your-CULTURE" />
NoWar
  • 36,338
  • 80
  • 323
  • 498
0

Another way to force decimal parsing at the backend side for "en-US" culture is to set it somewhere in the startup of the application (if you don't want to do it through web.config).

For ASP.NET MVC it may be e.g. Global.asax, whie for ASP.NET Core MVC it may be Startup.cs.

var ci = new CultureInfo("en-US"); 
CultureInfo.CurrentCulture = ci;
CultureInfo.DefaultThreadCurrentCulture = ci;
infografnet
  • 3,749
  • 1
  • 35
  • 35
-1

Try changing

var price = Number($('#price').val().toFixed(2));

To

var price = parseFloat($('#price').val()).toFixed(2);
Anderson Pimentel
  • 5,086
  • 2
  • 32
  • 54
-1

Try changing:

    public class test
    {
        public decimal Price { get; set; }
    }

    [HttpPost]
    public void Test(test whatever)
    {
        // I have tried with decimal, double and double?.     
    }

Care about property Name and dataType: 'json' in Ajax call

RomainV
  • 24
  • 2
-1

For me only this way works:

type: "POST",
data: 'price': parseFloat($(#price).val()).toFixed(2).replace(".", ","),
success: function(data){
...
}

It probably depend from your current culture in environment. I hope it will helps someone.

gutkol
  • 1
  • Code only answers are discouraged. Please add some explanation as to how this solves the problem, or how this differs from the existing answers. [From Review](https://stackoverflow.com/review/late-answers/22291462) – Nick Feb 24 '19 at 02:03
-1

I had to bind more complex model, so stringify solution was not what I wanted. So i found this article which shows how to extend default model binder to accept decimals.

Here is the code from haacked.com:

First you extend IModelBinder:

using System;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Http.Controllers;

public class DecimalModelBinder : IModelBinder {
    public object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext) {
        ValueProviderResult valueResult = bindingContext.ValueProvider
            .GetValue(bindingContext.ModelName);
        ModelState 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 you register this binder:

protected void Application_Start() {
    AreaRegistration.RegisterAllAreas();
    
    ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());

    // All other stuff ...
}
NoWar
  • 36,338
  • 80
  • 323
  • 498
gtu
  • 707
  • 1
  • 10
  • 22