82

I want to send data of object to my Web API. The API accepts a parameter of class, which properties are type of int and string.

This is my class:

public class deneme
{
   public int ID { get; set; }
   public int sayi { get; set; }
   public int reqem { get; set; }
   public string yazi { get; set; }
}

This is my JSON object:

{
   "id":0,
   "sayi":"9",
   "reqem":8,
   "yazi":"sss"
}

I want the api read the property "sayi" as integer. but because it cant, it gives the error:

The JSON value could not be converted to System.Int32. Path: $.sayi

How could I solve this problem?

fatihyildizhan
  • 8,614
  • 7
  • 64
  • 88
ali suleymanli
  • 1,033
  • 1
  • 9
  • 12

9 Answers9

114

For Asp.Net Core 3.0, it uses System.Text.Json for serialization and deserialization.

For using old behavior, you could use Json.NET in an ASP.NET Core 3.0 project by referencing Json.NET support.

Short Answer:

  1. Install Microsoft.AspNetCore.Mvc.NewtonsoftJson which is preview version.
  2. Change to services.AddControllers().AddNewtonsoftJson();
Edward
  • 28,296
  • 11
  • 76
  • 121
  • 2
    Perfect, thanks. Question is, why couldn't Microsoft just use the most downloaded NuGet package... – Adriaan Davel Nov 07 '19 at 07:03
  • 2
    It's not as efficient or performant. Newtonsoft is a great package as it covers a huge array of use-cases. With that large number of use-casts, comes performance overhead costs. Microsofts was very focused with theirs. It was performance driven for aspnetcore. – Johnathon Sullinger Nov 10 '19 at 06:35
  • 2
    I just had to go this route to get my object to deserialize properly. For some reason `Microsoft.AspNetCore.Mvc.NewtonsoftJson` doesn't show up in the package manager and had to manually install it with `Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.0.0`. It'll indicate the package can be updated to 3.1.0, but it requires net core 3.1, which is still in prerelease as of writing this comment. Writing this in hopes it helps someone else who ran into this issue! – Zulukas Dec 03 '19 at 18:11
  • Thank you. I think this kind of error shouldn't happen ever in default setup, it is not normal to submit { num: 0.2 } to the server get error of this kind with default setup.. – Vitaly Leskiv Oct 24 '22 at 14:20
32

Starting in .NET 5, there is an option to deserialize numbers that are represented as JSON strings instead of throwing an exception.

using System.Text.Json;
using System.Text.Json.Serialization;

var options = new JsonSerializerOptions()
{
     NumberHandling = JsonNumberHandling.AllowReadingFromString |
     JsonNumberHandling.WriteAsString
};

// serialize
string denemeJson = JsonSerializer.Serialize<Deneme>(deneme, options);

// deserialize
Deneme denemeDeserialized = JsonSerializer.Deserialize<Deneme>(denemeJson, options);
HRKoder
  • 1,646
  • 15
  • 11
29

First you should create a JsonConverter for it:

using System;
using System.Buffers;
using System.Buffers.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace sample_22_backend.Converters
{
    public class IntToStringConverter : JsonConverter<int>
    {
        public override int Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
                if (Utf8Parser.TryParse(span, out int number, out int bytesConsumed) && span.Length == bytesConsumed)
                {
                    return number;
                }

                if (int.TryParse(reader.GetString(), out number))
                {
                    return number;
                }
            }

            return reader.GetInt32();
        }

        public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString());
        }
    }
}

Then use it this way on your model's properties:

[JsonConverter(typeof(IntToStringConverter))]
public int GenreId { set; get; }

Or you can add it globally:

services.AddControllers()
        .AddJsonOptions(options => 
                options.JsonSerializerOptions.Converters.Add(new IntToStringConverter()));
VahidN
  • 18,457
  • 8
  • 73
  • 117
  • 2
    Shouldnt it be stringtointconvertor? – Jay Jay Jay Apr 09 '20 at 22:32
  • Is there any non custom way to do this yet. I would think they would fix this and allow people to pass integers without quotes. This breaks many existing APIs. I think this is the best answer as I feel using Newtonsoft isn't moving forward in the right direction – Dan Parker May 21 '20 at 21:06
  • It's scheduled for the next version of the .NET: https://github.com/dotnet/runtime/issues/30255 – VahidN Jun 04 '20 at 04:08
  • You can also pass this as a part of the JsonSerializerOptions when calling the Deserialize method as such: var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, Converters = { new API.Helpers.StringToGuidConverter() } }; StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream); string json = reader.ReadToEnd(); return JsonSerializer.Deserialize(json, options); – Sergio A. Oct 27 '21 at 20:34
10

In .NET CORE 3.X the serialize/deserialize process is done using System.Text.Json not Newtonsoft Json. Edward's answer did not work entirely for me:

  1. Installing from Nuget Manager Microsoft.AspNetCore.Mvc.NewtonsoftJson won't make step 2 to compile.
  2. Yes, add in Startup services.AddControllers().AddNewtonsoftJson(); - you will receive an error, AddNewtonsoftJson() not recognized.

At least this happened to me.

As a fix, uninstall what you've installed at step 1. In package manager console, run: Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.0.0-preview8.19405.7 . This worked for me.

Cata Hotea
  • 1,811
  • 1
  • 9
  • 19
3

Better parse the values to Integer and send data to Server Side application from your Client side application, This worked for me. Happy Coding!!

{
  "id":parseInt(0),
  "sayi":parseInt(9),
  "reqem":parseInt(8),
  "yazi":"sss"
 }
Anglesvar
  • 1,132
  • 8
  • 15
1

in js model, make sure your values are formatted as parseFloat();

Moustachio
  • 184
  • 2
  • 23
1

There is an another way: just create a DTO with the type string for number types and convert it into the controller or to the type that you need.

Alejandro
  • 83
  • 1
  • 2
1

FYI, I thought I was already implementing the suggested answer because I had the following in my Program.cs

builder.Services.AddControllersWithViews().AddJsonOptions(opt =>
                {
                    opt.JsonSerializerOptions.PropertyNamingPolicy = null;
                    opt.JsonSerializerOptions.AllowTrailingCommas = true;
                    opt.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString |
                        JsonNumberHandling.WriteAsString;                    
                    opt.JsonSerializerOptions.IncludeFields = true;
                });

For some reason it is being ignored in my controller, I don't know why, I had to implement the suggested fix by HRKoder before it would work.

Post Impatica
  • 14,999
  • 9
  • 67
  • 78
-3

May face this issue in .net core, You can change the datatype from int to int64

Gsanto
  • 1
  • 4