Convert Json object into custom Object - c#

I have a massive json file that i am parsing. But I have a problem when parsing it.
There is a field in the file that looks similar:
"pageTitle": {
"en": "Some content here...."
},
I store this as a dictionary:
[JsonProperty("pageTitle")]
public Dictionary<string, string> PageTitle { get; set; }
But sometimes this field is empty, and when it is the Json.Net method
ToObject<MyCustomClass>()
Fails when trying to convert pageTitle because it appears to be an empty array and not an object. Is there a JsonPropery to make it ignore this empty array and just carry on?

If you would like to ignore the null values, then it is possible to decorate the property as follows:
[JsonProperty("pageTitle", NullValueHandling = NullValueHandling.Ignore)]
If the JSON string being parsed is an empty array [] or an invalid input, you might have to write a custom converter by extending the abstract class, JsonConverter or extending one of the inbuilt converters in Newtonsoft.Json.Converters and invoke it as:
var obj = JsonConvert.DeserializeObject<MyCustomClass>(jsonString, new CustomConverter());
OR
Handle the exception that happens during deserialization as follows:
var obj = JsonConvert.DeserializeObject<MyCustomClass>(json, new
JsonSerializerSettings
{
Error = HandleError
});
Handler:
private static void HandleError(object sender, ErrorEventArgs e)
{
// Get the error message using 'e.ErrorContext.Error.Message'
// e.ErrorContext.OriginalObject will give you the object/property that failed to deserialze
e.ErrorContext.Handled = true;
}

Related

JSON Deserialization for dictionary with arrays

I have a Python code that sends this JSON through MQTT.
message = {
"name":"Alex",
"date": 2021,
"activity":["act1","act2","act3"],
}
Then I receive and Deserialize it in a C# script
public void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
var Message = System.Text.Encoding.Default.GetString(e.Message);
Dictionary<string, string> MessageDICT = JsonConvert.DeserializeObject<Dictionary<string, string>>(Message);
}
The keys "name" and "date" has no problem being deserialized into the dictionary. However the error comes with "activity" due it being an array. Where it states "Unexpected character encountered while parsing value:[". I have seen methods where they deserialize it separately (where the array is sent in a different message), however this is not what I want. Is there a way I can deserialize the message as a whole?
Thanks.
You have your dictionary declared as <string, string>, but "activity" is an array. So this is why it does not work.
If you want to keep using a dictionary, then you can instead declare it as <string, object> and then it will work for any type of data. But you will need to then check what Type it is before you later try to use it.
Dictionary<string, object> MessageDICT = JsonConvert.DeserializeObject<Dictionary<string, object>>(message);
You can then access it like this:
object first = ((JArray)MessageDICT["activity"])[0];
But if possible, you should try to use a fixed class for the data and deserialize that.
Otherwise, maybe a dynamic is better.
Hi why not use a class to read the json
public class Message
{
public string name {get;set;}
public string date {get;set;} //actually, this looks like an int the json, however...
public string[] activity {get;set;}
}
usage
var res = JsonConvert.DeserializeObject<Message>(message);

Serializing plain values and objects with JObject.FromObject

I have problem with serializing objects using Newtonsoft.JSON. I have a method which creates EventGridEvent object:
public EventGridEvent CreateEvent(object data) =>
new EventGridEvent
{
Id = Guid.NewGuid().ToString(),
EventTime = DateTime.Now,
Data = JObject.FromObject(data, JsonSerializer),
...other properties
}
When the method is called with "proper" object, everything serializes properly. The problem is if the data is a plain value i.e. integer or string. In this case I get an exception Object serialized to Integer. JObject instance expected. How to detect if object can be serialized with JObject.FromObject and if not use its plain value (without using try/catch)?
If EventGridEvent.Data can hold any type of JSON value, you should modify it to be of type JToken and use JToken.FromObject(Object, JsonSerializer), i.e.:
public class EventGridEvent
{
public JToken Data { get; set; }
// ...other properties
}
And then do
Data = JToken.FromObject(data, JsonSerializer),
A JToken
Represents an abstract JSON token.
It can be used to hold the JSON representation of any JSON type including an array, object, or primitive value. See: JSON.NET: Why Use JToken--ever?.
If you need to serialize a nullable value like an int? or string, JToken.FromObject() will throw an error. I've found that the implicit operator (called by casting) works better.
string s = null;
int? i = null;
JObject obj = new JObject();
// obj.Add(JToken.FromObject(s)); // throws exception
// obj.Add(JToken.FromObject(i)); // throws exception
obj.Add((JToken)s); // works
obj.Add((JToken)i); // works

C# Constructor from deserialized json?

I have a class which represent a json api. I have created a constructor that is using switched enums to select how the object is to be populated. One is for the minimum equivalent json object. Another is intended populate the properties by reading in from a file. So, I can read the file into a string and deserialize it, but what do I do next to populate the properties?
// this code is in the constructor
string text = System.IO.File.ReadAllText(fileName);
this.???? = JsonConvert.DeserializeObject<MyObject>(text); // MyObject is the object the constructor is working on
Can I cast the deserialized text into the object's properties?
Sorry for asking something that has probably already been asked, but I don't know if I am even asking the question properly (let alone searching for it). Thanks...
Not tested, but I think you could do something like this:
public MyObject(MyEnum e)
{
switch(e)
{
case MyEnum.ValueThatMeansWeDeserializeFromJSON:
string text = System.IO.File.ReadAllText(fileName);
var serializer = new JsonSerializer();
serializer.Populate(new JsonTextReader(new StringReader(text)), this);
break;
}
}
Populate will take an existing object and try to deserialize the properties from JSON into that object (as opposed to DeserializeObject which will create a new object.
As I mentioned in a comment, use a factory instead of the switch in the constructor.
If you want to keep it in the constructor use automaper and do this instead
public class MyObject
{
public MyObject()
{
}
public MyObject(Enum e)
{
string text = System.IO.File.ReadAllText(fileName);
var source = JsonConvert.DeserializeObject<MyObject>(text);
Mapper.CreateMap<MyObject, MyObject>();
Mapper.Map(source, this);
}
public string Name { get; set; }
}

Determining object "type" during json deserialization

While trying to de-serialize a complex JSON object (JIRA issue) into an object containing a dictionary of type string-Field I've hit a bit of a bump.
While I can de-serialize various pre-determined object types (standard), I'm having a bit of a harder time with the custom fields, which could be of various types (they all begin with customfield_ followed by a set of numbers).
The custom fields can be floats, strings, booleans, objects and arrays of objects. The latter of these is causing me issues since I can't seem to determine what the object is before I de-serialize it.
I've searched for a way to perhaps "peek" at the data in the object before de-serializing as one of the fields contains information specific to it's type. This is all so I can determine the type of the object and tell Json.Net what to de-serialize it as.
I've considered parsing the JSON string before serialization to get the information, or maybe just when hitting this particular case, but maybe there is a better way?
Thanks in advance for any advice on this.
You can deserialize to an object with Json.Net. Here's a quick and dirty example:
using System;
using Newtonsoft.Json;
namespace Sandbox
{
class Program
{
private static void Main(string[] args)
{
var nestDto = new Dto
{
customfield_1 = 20,
customfield_2 = "Test2"
};
var dto = new Dto
{
customfield_1 = 10,
customfield_3 = new[] { nestDto },
customfield_2 = "Test"
};
var jsonString = JsonConvert.SerializeObject(dto);
Console.WriteLine(jsonString);
var fromJsonString = JsonConvert.DeserializeObject<Dto>(jsonString);
Console.WriteLine(fromJsonString.customfield_3[0].customfield_2); //Outputs Test2
Console.ReadKey();
}
}
class Dto
{
public int customfield_1 { get; set; }
public string customfield_2 { get; set; }
public Dto[] customfield_3 { get; set; }
}
}
Instead of peaking, you can deserialize as the same type as JSON.net uses for ExtensionData explicitly. For example:
if (reader.TokenType == JsonToken.StartArray)
{
var values = serializer.Deserialize<List<Dictionary<string, JToken>>>(reader);
objectContainer = ClassifyAndReturn(values);
}
private ObjectType ClassifyAndReturn(List<Dictionary<string, JToken>> values)
{
if (values.First().ContainsKey("self"))
{
string self = values.First()["self"].Value<string>();
if (self.Contains("customFieldOption"))
//... Then go into a series of if else cases to determine the object.
The representation of the objects are given as a Dictionary of string to JToken, which can then easily be checked and assigned manually or in some cases automatically deserialized (in the case one of the fields is another object).
Here is what an object constructor could look like:
internal myobject(Dictionary<string, JToken> source)
{
Self = source["self"].Value<string>();
Id = source["id"].Value<string>();
Value = source["value"].Value<string>();
}

How to map a data contract to refer to correct fields in a JSON object?

I'm recieving a JSON object that looks like the example below.
{
"name1":{"name1a":"value1a","name1b":"value1b"},
"name2":{"name2a":"value2a","name2b":"value2b"}
}
I've set up a data contract for it (since I only need to access a single data field at the moment) like this.
[DataContract]
public class MyThingy
{
[DataMember(Name="name1b")]
public string Name1b { get; set; }
public MyThingy() { }
public MyThingy(String name1b)
{
Name1b = name1b;
}
}
When I've serialized the object, I try to print it out (which works, since I'm getting a string description of the class) and them the field Name1b. The last part doesn't work and I'm getting null there. My guess is that I must have mapped the data contract wrongly but I can't see how to correct it.
How should the MyThingy class be declared?
My JSON object is fetched as described in this post.
I would use JavaScriptSerializer here,
string json = #"{
""name1"":{""name1a"":""value1a"",""name1b"":""value1b""},
""name2"":{""name2a"":""value2a"",""name2b"":""value2b""}
}";
var obj = new JavaScriptSerializer()
.Deserialize<Dictionary<string, Dictionary<string, string>>>(json);
Console.WriteLine(obj["name1"]["name1b"]);
You can also use Json.Net and dynamic together
dynamic obj = JsonConvert.DeserializeObject(json);
Console.WriteLine(obj.name1.name1b);

Categories