Skip to content

In ASP.Net Core 5 MVC Controller, when passed a JSON object FromBody that contains a decimal the model is always null

Passing in this json works:

{
  "products": [
    {
      "barcode": "1",
      "quantity": 1,
      "name": "Barratt Fruit Salad Chews 400 pc box",
      "unitPrice": 8,
      "totalPrice": 8,
      "isInBuyTwoGetOneFreePromotion": false
    }
  ]
}

Passing in this json does not work:

{
  "products": [
    {
      "barcode": "8",
      "quantity": "4",
      "name": "Bonds dinosaurs",
      "unitPrice": 0.5,
      "totalPrice": 2,
      "isInBuyTwoGetOneFreePromotion": true
    }
  ]
}

The reason is the decimal being passed.

My controller has this method

[HttpPost]
        public async Task<JsonResult> UpdateStockAndLogInvoice([FromBody] Invoice invoice)

It references this model:

public partial class Invoice
    {
        [JsonProperty("products")]
        public List<InvoiceItem> Products { get; set; }
    }

    public partial class InvoiceItem
    {
        [JsonProperty("barcode")]
        public string Barcode { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("quantity")]
        public int Quantity { get; set; }

        [JsonProperty("totalPrice")]
        public long TotalPrice { get; set; }

        [JsonProperty("unitPrice")]
        public long UnitPrice { get; set; }

        [JsonProperty("isInBuyTwoGetOneFreePromotion")]
        public bool IsInBuyTwoGetOneFreePromotion { get; set; }
    }

I believe the issue is in converting from the float used in javascript to the long used in C#, but I have scoured the internet and cannot work out how to get my model being passed in to not be null.

Any suggestions gratefully accepted!

Answer

Your failed JSON is not compatible with your InvoiceItem class in at least two ways:

  • Quantity is not a string.
  • UnitPrice is a long, it can’t accept floating point values.

During request processing the MVC model binder attempts to deserialize the JSON body into the requested InvoiceItem type and fails. It treats this failure as if the body was empty, checks whether you’ve told it to allow empty bodies (which it does by default) and continues on as if no body had been supplied.

To fix this you need to resolve the difference between your client side and server side models. Since JavaScript really doesn’t care about types you have to be particularly careful to ensure that you are managing the client side data correctly, otherwise it’s not going to deserialize correctly on the server side. Different ASP.NET MVC versions may have different restrictions when it comes to the translations it will handle automatically, but valid JSON that matches your model will always work.

So… update your server side model to use decimal for the UnitPrice and TotalPrice properties, then fix your client side javascript to put the right value types in.