JsonConvert.DeserializeObject error while deserializing a string - c#

I am trying to deserialize a json string that is coming from a js code, the data holds the json string that I want to deserialize.
The coming string is:
{"metalRingID":"FB11111","birdData":[{"longitude":-3.0851070084624497,"latitude":51.02832183751735,"gridRef":"ST2426","date":"2020-01-05T00:00:00"},{"longitude":-2.233409881591797,"latitude":51.5276985168457,"gridRef":null,"date":"2020-01-02T00:00:00"},{"longitude":-2.3790299892425537,"latitude":51.4547004699707,"gridRef":null,"date":"2020-01-03T00:00:00"},{"longitude":-1.6884700059890747,"latitude":51.68299865722656,"gridRef":null,"date":"2020-01-05T00:00:00"}]}
This is the model to hold that data:
using System;
using Newtonsoft.Json;
namespace BirdProject.Model.ViewModel
{
public class birdDataSolutionVM
{
[JsonProperty("metalRingID")]
public string metalRingID;
[JsonProperty("birdData")]
public List<birdRecordVM> birdData;
}
}
This is the line that should do the job.
var birdRecords = JsonConvert.DeserializeObject<List<birdDataSolutionVM>>(data);
The error I am receiving is the next:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.List`1[BirdProject.Model.ViewModel.birdDataSolutionVM]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.\nTo fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object.\nPath 'metalRingID', line 1,
position 15.

You should be deserializing into the type, not an array of the type. It's a single object containing an array, but the root json is not an array.
var birdRecords = JsonConvert.DeserializeObject<birdDataSolutionVM>(data);

Related

safe Serialize and Deserialize with Newtonsoft.Json

I have a code that takes messages of any type and serialize them into the DB, while saving the type of the message and the serialized json string.
I have a side process that should deserialize the messages later on and send them to the queue.
To perform the serialization and deserialization I use JsonConvert of Newtonsoft.Json:
For deserialization I use the following method:
object? DeserializeObject(string value, Type type)
For serialization I use the following method:
string SerializeObject(object? value)
I have the following questions:
A. I saw that in case DeserializeObject receives a wrong type name it still deserialize the object but his type is Newtonsoft.Json.Linq.JObject and not the type I passed into the method, I expected it will throw an exception, this behavior is very bad for us, is there any way to cause the deserialize to throw exception in this scenario?
B. Is the code below secured? I saw that the library has variabilities such as depicted here
private void StackOverflowQuestion()
{
Bus.Employees.Messages.LevelCreated levelCreated = new Bus.Employees.Messages.LevelCreated
{
Name = "director",
};
//var messageType = levelCreated.GetType().AssemblyQualifiedName;
string messageData = JsonConvert.SerializeObject(levelCreated);
//Deserialize with type that is not correct
object deserializeMessaged = DeserializeMessage("my cool type which does not exists!", messageData);
string theType = deserializeMessaged.GetType().FullName;//theType = Newtonsoft.Json.Linq.JObject
}
private object DeserializeMessage(string messageType, string messageSerializedData)
{
Type type = Type.GetType(messageType);
return JsonConvert.DeserializeObject(value: messageSerializedData, type);
}

Json array exception

I create a Json file and insert some objects of my class inside it, like this:
private async void Save_Clicked(object sender, EventArgs e)
{
Note NoteNew = new Note
{
FraseGiorno = obj1.FraseGiornaliera,
Nota = TestoNota.Text,
Data= DateTime.Today.ToString().Remove(10,9),
};
File.WriteAllText(NotesFile, JsonConvert.SerializeObject(NoteNew));
}
Then when I try to read the file and deserialize the json I get this exception. how could i solve?
string NotesFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Note.json");
ObservableCollection<Note> listNote = new ObservableCollection<Note>();
FraseClass obj1;
public NotePage(FraseClass obj1)
{
InitializeComponent();
this.obj1 = obj1;
if (File.Exists(NotesFile))
{
listNote = JsonConvert.DeserializeObject<ObservableCollection<Note>>(File.ReadAllText(NotesFile));
CollectionNote.ItemsSource = listNote;
}
}
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.ObjectModel.ObservableCollection`1[MotiVApp.NotePage+Note]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'FraseGiorno', line 1, position 15.'
I don't understand why the exception refers to the 'FraseGiorno' property
You are serializing an object into the file, but deserializing into a collection.
If you absolutely must use an ObservableCollection, separate the initialization and deserialization steps:
var note = JsonConvert.DeserializeObject<Note>(File.ReadAllText(NotesFile));
listNode.Add(note);
CollectionNote.ItemsSource = listNote;

Can't deserialize JSON to Object [duplicate]

This question already has an answer here:
Cannot deserialize the current JSON array (e.g. [1,2,3])
(1 answer)
Closed 2 years ago.
I'm doing some testing in my program and I wanted to transform APIGatewayProxyResponse into a object to access it's values.
So an example of what my APIGatewayProxyResponse.Body (it's a string) looks like:
"[{"date": "2020-03-06", "value": 35},{"date": "2020-03-09", "value": 233}]"
I wanted to turn this into a dictionary at first, but I realized that perhaps it's not possible because a dictionary has unique key values and here I have a "date" and "value" properties that aren't unique.
var dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(APIGatewayProxyResponse.Body);
Had a error, which proved my concern:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.String]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
So I made an ResponseObject to achieve the same result
public class ResponseObject
{
public string date { get; set; }
public double value { get; set; }
}
var dic = JsonConvert.DeserializeObject(APIGatewayProxyResponse.Body,typeof(ResponseObject));
But had the same error! I don't understand, the browser can look at the response and recognises it's a JSON format, so why ins't the same happening in in ASP.NET?
Because your Json is an array, So, you can Deserialize with IEnumerable type.
Try this:
var dic = JsonConvert.DeserializeObject<IEnumerable<ResponseObject>>(APIGatewayProxyResponse.Body);

Getting A List From Service Async

While trying to get list from an url, program stops and throw an exception like that
An exception of type 'System.AggregateException' occurred in mscorlib.dll but was not handled in user code
also
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[WebAPIDemo.Models.Person]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'Message', line 1, position 11.
I thought its because of using IEnumerable<MyObject> in my program but when I use only MyObject it goes away from this point but it crush into somewhere else.
I'm stuck now.
Here is my code:
CONTROLLER.CS:
private IEnumerable<Person> CallPersonListServiceAsync(HttpClient ins, string url)
{
var content = ins.GetAsync(url).Result.Content;
var personsList = content.ReadAsAsync(typeof(IEnumerable<Person>)).Result as IEnumerable<Person>;
return personsList;
}
PERSON.CS:
public class Person
{
public string name { get; set; }
public string surname { get; set; }
public DateTime dob { get; set; }
}
Is it really happening that because I'm using IEnumerable or something different. Thanks
The error is telling you that the JSON you're receiving is an object, not a collection. So you have to deserialize it to an object, not a collection. Unless the JSON is very different from what you expect (that is, not a Person at all) then you would simply deserialize it to a Person:
var result = content.ReadAsAsync(typeof(Person)).Result as Person;
Which would of course necessitate changing the return type (and name) of your method:
private Person CallPersonServiceAsync(HttpClient ins, string url)
Alternatively, instead of changing the method signature you could manufacture a list from that single person and return that:
return new List<Person> { result };
Additionally, the async nature of your code is very broken. For one thing, you are calling .Result explicitly which is almost always the wrong approach. Second, your method's name advertises it as an async method but it's not async at all.
You can correct both of these problems by making use of async and await:
private async Task<Person> CallPersonServiceAsync(HttpClient ins, string url)
{
var content = (await ins.GetAsync(url)).Content;
var result = (await content.ReadAsAsync(typeof(Person))) as IEnumerable<Person>;
return result;
}

JSon.NET deserializing object doesn't work

So I have a Client-Server application that is using this class for communication, it contains an object so I can send any kind of data between server and client:
public class comObj
{
public eDisconnectedReason dcReason;
public object payload;
}
Before sending it through the Socket I will serialize it using JSon.Net, e.g.:
string jsonString = JsonConvert.SerializeObject((new Common.comObj() { dcReason = Server.disconnectedReason, payload = Data }), Formatting.None);
now the server receives exactly the string that was sent by the client:
sent string: "{\"dcReason\":4,\"payload\":{\"msg\":\"hi\"}}"
received string: "{\"dcReason\":4,\"payload\":{\"msg\":\"hi\"}}"
however when I try to deserialize the received string into the original comObj:
Common.comObj rcvdObj = JsonConvert.DeserializeObject<Common.comObj>(rcvdString);
rcvdObj.payload is of type Newtonsoft.Json.Linq.JObject instead of object.
Let us start by considering your JSON input:
{
"dcReason": 4,
"payload": {
"msg": "hi"
}
}
Using Json.NET you have two key ways of deserializing JSON data. You can:
Deserialize it into a specific concrete type
You can deserialize it into the generic JToken type. (In your case, it instantiates a JObject -- a subclass of JToken -- because JSON.Net recognized that the JSON input specified an object, as opposed to a primitive type or an array)
In your case, you actually ended up with a hybrid of both approaches. Since you specified a specific type for the root object, it returned an instance of comObj. Since you merely specified object as the type of the property payload, Json.NET did its best and simply reverted to option 2) and gave you an instance of JObject, which contains the data such as msg.
You have two options to solve your problem. You can:
Interrogate the payload property as a JObject, like you would have had to do for the entire JSON body if you had not used option 1).
Define a concrete type to represent the payload property. I strongly recommend this approach, as it is considerably more typesafe and also easier to work with.
To achieve the former, you can use faclities such as o["msg"] -- essentially like a dictionary.
To achieve the latter -- which I would recommmend -- simply define a type for payload. In other words, change you code to:
public class comObj
{
public eDisconnectedReason dcReason;
public Payload payload;
}
public class Payload
{
public string msg { get; set; }
}
Now when you deserialize your JSON, you'll be able to use the syntax:
Console.WriteLine(rcvdObj.payload.msg);
And -- importantly -- if you later decide to rename msg in your JSON payload to, say, message you will be able to properly refactor the property msg of payload to message and expect all usages to be fixed. This is obviously less robust when using strings.

Categories

Resources