JArray Deserialize only first property value to Object - c#

I have this json file:
[
{
"blah" : "some text here",
"hidden" : false,
},
{
"blah" : "some other text",
"hidden" : false,
}
]
I load it into a JArray and then I want to use to ToObject method to deserialize the data to a custom Class:
public class LookupItem
{
public string DisplayMember { get; set; }
}
the display member I want it to be the value of the first property that appears on the objects. So that:
var a = myJArray.ToObject(List<LookupItem>);
would return
a[0].DisplayMember ---> some text here
a[1].DisplayMember ---> some other text
I thought I could use a
[JsonProperty(Order = 0)]
attribute but it doesn't seem to be working for deserialization only for serialization. (the real issue is that I don't know the first property's key value upfront).

Inconsitent JSON
If there is no consistency in your JSON, you can deserialize the whole thing to an object.
var items = JsonConvert.DeserializeObject("Your JSON"));
Then cast it to a JContainer and loop through it and create your LookupItem objects. Code below assumes the first property is what you want:
var luItems = new List<LookupItem>();
var item = ((Newtonsoft.Json.Linq.JContainer)items).ToList()[0];
((Newtonsoft.Json.Linq.JContainer)items).ToList().ForEach(x =>
luItems.Add(new LookupItem { DisplayMember = x.First.First().ToString() }));
Consitent
If there is consitency, then create a C# class to represent objects of your JSON:
public class Class1
{
public string blah { get; set; }
public bool hidden { get; set; }
}
Then deserialize and create LookupItem instances:
var consitentItems = JsonConvert.DeserializeObject<Class1[]>(File.ReadAllText("Files/Json.txt"));
var consistentLookupItems = new List<LookupItem>();
consitentItems.ToList().ForEach(x =>
consistentLookupItems.Add(new LookupItem { DisplayMember = x.blah }));

using Newtonsoft.Json.Linq.JArray
take All JTokens
Newtonsoft.Json.Linq.JArray jarr = (Newtonsoft.Json.Linq.JArray)(JsonConvert.DeserializeObject(yourJsonScript));
List<LookupItem> myList= New List<LookupItem>();
jarr.ToList().ForEach(jtoken =>
{
myList.Add(new LookupItem(){DisplayMember=jtoken.ElementAt(0).ToObject<string>()});
});

Related

Serialize a JSON object without property name having a list of custom object in C#

I have model as below:
public class CustomModel
{
public string Data1 { get; set; }
public string Data2 { get; set; }
}
public class root
{
public List<CustomModel> data { get; set; }
}
My payload is as below:
List<CustomModel> cms = new List<CustomModel>();
CustomModel cm1 = new CustomModel();
cm1.Data1 = "a";
cm1.Data2 = "b";
cms.Add(cm1);
CustomModel cm2 = new CustomModel();
cm2.Data1 = "D";
cm2.Data2 = "E";
cms.Add(cm2);
BaseClass baseClass = new BaseClass();
baseClass.data = cms;
My JSON is:
var json = new JavaScriptSerializer().Serialize(baseClass);
And Result is:
{"data":[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]}
BUT I need: without the "data" property as below:
{[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]}
I tried the below function:
public static IEnumerable<object> GetPropertyValues<T>(T input)
{
return input.GetType()
.GetProperties()
.Select(p => p.GetValue(input));
}
Like
var value_only = GetPropertyValues(baseClass);
var json = new JavaScriptSerializer().Serialize(value_only);
BUT it returns [[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]]
Is there anywasy to do it other than manually adding? Please help.
Note that {[{"data1":"a","data2":"b"},{"data1":"D","data2":"E"}]} is not valid json. In Json objects, data/values are organized by (named) properties.
However, here you seem to want a (root) Json object containing a value being Json array, but that value is not associated with a Json object property, thus not being valid Json.
If you really want invalid Json, i suggest you serialize the List<CustomModel> instance instead of the root model instance, resulting in a Json array, and then manually adding the surrounding { and } to the serialized Json string, thus giving you your desired invalid Json result:
var json = new JavaScriptSerializer().Serialize(baseClass.data);
var desiredResult = "{" + json + "}";
you don't need root class (or base class you must to deside what is name. Just use
var json = new JavaScriptSerializer().Serialize(cms);
PS.
And it is time to select a modern serializer.

How can I custom a .Net Json serialize settings to handle json key fields? [duplicate]

I have the following JSON string:
{
"values": {
"details": {
"property1": "94",
"property2": "47",
"property3": "32",
"property4": 1
},
count: 4
}
}
I am going to map this to the following model:
public class Details
{
public string property1 { get; set; }
public string property2 { get; set; }
public string property3 { get; set; }
public int property4 { get; set; }
}
public class Values
{
public Details details { get; set; }
public int count { get; set; }
}
public class RootObject
{
public Values values { get; set; }
}
I want to be able to map the these property names to different names at runtime when deserializing this JSON string like this:
JsonConvert.DeserializeObject<RootObject>(jsonString);
For example, in the deserialization process, I want the deserialize the name of "property1" to "differen_property_name1" or "differen_property_name2" or "differen_property_name3".
Because I am choosing the new name at runtime (the new name to which I will change the "property1" name to), I can't use the solution using JsonPropertyAttribute, as suggested here:
.NET NewtonSoft JSON deserialize map to a different property name
One of the answers of the above question (Jack's answer) uses inheritance of DefaultContractResolver but it doesn't seem to work in that case.
Update
Later on, I needed to serialize the object I got from the deserialization and map the properties to different property names, defined at runtime.
I used the same method as Brian proposed to do the serialization:
I used the dictionary to map my new property names:
var map = new Dictionary<Type, Dictionary<string, string>>
{
{
typeof(Details),
new Dictionary<string, string>
{
{"property1", "myNewPropertyName1"},
{"property2", "myNewPropertyName2"},
{"property3", "myNewPropertyName3"},
{"property4", "myNewPropertyName4"}
}
}
};
and then I used Brian's DynamicMappingResolver to serialize the object like this:
var settings = new JsonSerializerSettings
{
ContractResolver = new DynamicMappingResolver(map)
};
var root = JsonConvert.SerializeObject(myObjectInstance, settings);
You could use a custom ContractResolver to do this. Basically it is the same idea as putting a [JsonProperty] attribute on each class member for which you want to map to a different JSON property name, except you do it programmatically via the resolver. You can pass a dictionary of your desired mappings to the resolver when setting it up just before deserializing.
Here is what the custom resolver code might look like:
class DynamicMappingResolver : DefaultContractResolver
{
private Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap;
public DynamicMappingResolver(Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap)
{
this.memberNameToJsonNameMap = memberNameToJsonNameMap;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
Dictionary<string, string> dict;
string jsonName;
if (memberNameToJsonNameMap.TryGetValue(member.DeclaringType, out dict) &&
dict.TryGetValue(member.Name, out jsonName))
{
prop.PropertyName = jsonName;
}
return prop;
}
}
To use the resolver, first construct a Dictionary<Type, Dictionary<string, string>> containing your mappings. The outer dictionary's key is the the class type(s) whose properties you want to map; the inner dictionary is a mapping of the class property names to JSON property names. You only need to provide a mapping for the properties whose names don't already match the JSON.
So, for example, if your JSON looked like this (notice the changed names of the properties inside the details object)...
{
"values": {
"details": {
"foo": "94",
"bar": "47",
"baz": "32",
"quux": 1
},
count: 4
}
}
...and you wanted to map it to the classes in your question, you would create the dictionary like this:
var map = new Dictionary<Type, Dictionary<string, string>>
{
{
typeof(Details),
new Dictionary<string, string>
{
{"property1", "foo"},
{"property2", "bar"},
{"property3", "baz"},
{"property4", "quux"}
}
}
};
The last step is to set up the serializer settings with a new resolver instance, giving it the mapping dictionary you just constructed, and then pass the settings to JsonConvert.DeserializeObject().
var settings = new JsonSerializerSettings
{
ContractResolver = new DynamicMappingResolver(map)
};
var root = JsonConvert.DeserializeObject<RootObject>(json, settings);
Here is a demo: https://dotnetfiddle.net/ULkB0J
Why do this in one step? Why not deserialize into your standard object and then map them over dynamically using Automapper?
something like:
Mapper.Initialize(c =>
{
c.ReplaceMemberName("property1 ", "differen_property_name1");
});
If you don't want to use a custom ContractResolver to do this. Use [JsonProperty("")] to look for different variations of the property name and return with another property like this:
public class Details
{
private string _property1;
private string _property2;
[JsonProperty("property1")]
public string prop1 {get;set;}
[JsonProperty("foo")]
public string foo {get;set;}
public string getProperty1
{
get {_property1=prop1??foo;return _property1;}
set{prop1=value;foo=value;}
}
[JsonProperty("property2")]
public string prop2 {get;set;}
[JsonProperty("bar")]
public string bar {get;set;}
public string getProperty2
{
get {_property2=prop2??bar;return _property2;}
set {prop2=value;bar=value;}
}
}
Demo here: https://dotnetfiddle.net/V17igc
I don't believe that JSON.net has any support for what you are looking for. You should instead deserialize the JSON into JObject if you don't know the format or some generic one if you do (for instance if the JSON always says property1 you can use a generic object to represent it).
Once you have your generic object then next you need to translate the fields. Any that aren't changeable can be done directly, but for anything else you will need to use Reflection.
Basically it involves getting the type (typeof(Details) or obj.GetType()) and then searching for the Property you want to update. Finally you should be able to find the setter method and call it supplying the original value out of your generic object.

JSON.NET deserialize object using all properties in JSON (overriding all initialized in the constructor) [duplicate]

This question already has answers here:
Populate object where objects are reused and arrays are replaced?
(2 answers)
Closed 4 years ago.
I have a class with some properties, one of them a list of items. All of them are initialized in the default parameterless constructor of the class. I only want to have to have this constructor that initalizes everything.
This is a case for many of my classes.
public class ExampleClass
{
public ExampleClass()
{
this.ListProperty = new List<int> { 1, 2 };
this.APropertyToBeNull = new TypeA();
this.BPropertyToBeNull = new TypeB();
}
public List<int> ListProperty { get; set; }
public TypeA APropertyToBeNull { get; set; }
public TypeB BPropertyToBeNull { get; set; }
}
I create an instance of this class, I set some of the properties to null and I modify the list property to have 2 items.
var instance = new ExampleClass();
instance.APropertyToBeNull = null;
instance.BPropertyToBeNull = null;
instance.ListProperty = new List<int> { 3 };
var raw = JsonConvert.SerializeObject(instance);
var deserialized = JsonConvert.DeserializeObject<ExampleClass>(raw, settings);
Assert.AreEqual(1, deserialized.ListProperty.Count);
Assert.IsNull(deserialized.APropertyToBeNull);
Assert.IsNull(deserialized.BPropertyToBeNull);
When I deserialize, I don't find a way of getting the item exactly as I serialized it. I got two options:
If I set the ObjectCreationHandling to Replace, the list deserializes fine, but the null properties are not null anymore. The constructor initialized everything, the deserialization replaced the list completely but it did not set the null properties to null.
If I set the ObjectCreationHandling to Auto or Reuse, the null properties are deserialized fine as null, but the list has the items that were initialized in the constructor plus the items in the JSON. I only want those in the JSON.
How do I get the exact same item I serialized without removing the initialization of all the properties in the constructor (I still want to have all of them initialized in case a new instance is created).
I have played with all possible settings of the serializer, and I don't find a solution.
As a further constraint, I don't want to add attributes to all of my classes. I have this problem for many of them.
You can use the [JsonProperty] attribute with the DefaultValueHandling property.
Given this class:
public class Foo
{
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public string Bar { get; set; }
public List<bool> Baz { get; set; }
public Foo()
{
Bar = "Not Null";
Baz = new List<bool>
{
false
};
}
}
And this JSON:
{ "baz" : [ true ] }
This code:
string json = "{ \"baz\" : [ true ] }";
var foo = JsonConvert.DeserializeObject<Foo>(json, new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Replace
});
Console.WriteLine(foo.Bar ?? "(null)");
foreach (var b in foo.Baz)
{
Console.WriteLine(b);
}
Will print:
(null)
True
Meaning the Bar string will be overwritten with the value from the JSON, being null since it's missing.

C#, How to pass property name from string parameter for Dynamic object

My API response will return a list of JSON objects and I need to verify the order of the list, so I write a function as follows. But I got a problem for the LINQ order by sentence, it only works when I specify the actual field, but I need pass this field name as a parameter. so something like
var expectedList = jObjList.OrderBy(x => x.parameterFieldName.ToString());
please give me some suggestions, many thanks.
public void VerifyOrderBy(string jsonString, string parameterFieldName)
{
List<dynamic> jObjList = JsonConvert.DeserializeObject<List<dynamic>>(jsonString);
var expectedList = jObjList.OrderBy(x => x.LastName.ToString());
Assert.IsTrue(expectedList.SequenceEqual(jObjList));
}
the JSON string looks like follows
[
{
"FirstName": "w3pCj",
"LastName": "mSJOV",
"IsDeleted": false
},
{
"FirstName": "rMnH7",
"LastName": "rMnH7",
"IsDeleted": false
},
{
"FirstName": "Jia",
"LastName": "Yu",
"IsDeleted": false
}
]
You can use the nameof() operator keyword like this:
jObjList.OrderBy(x => nameof(x.LastName));
UPDATE #1
Let's say we have a Person class:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsDeleted { get; set; }
}
Let's say we have a list of people:
var people =
JsonConvert
.DeserializeObject<List<Person>>(
File.ReadAllText("data.json", Encoding.UTF8)
);
We can have a parameter that will contain the property name we want to order by:
string parameterName = nameof(Person.LastName); // or simply "LastName"
We get a reference to that property:
PropertyInfo orderByProperty =
typeof(Person)
.GetProperties()
.SingleOrDefault(property => property.Name == parameterName);
Now we can order by the selected property:
var result = people.OrderBy(person => orderByProperty.GetValue(person)).ToList();
Please note:
Of course you should check if the orderByProperty is not null. :)
This will work only on in-memory objects (LINQ-to-Objects) but not on a DB set (LINQ-to-SQL, EF)
Do not forget to add the required using statement to be able to get the PropertyInfo:
using System.Reflection;
UPDATE #2
If you have such a simple json structure and you want to use dynamic objects for ordering then you can achieve it like this:
var people =
JsonConvert
.DeserializeObject<List<dynamic>>(
File.ReadAllText("data.json", Encoding.UTF8)
);
string parameterName = "LastName";
var result =
people
.OrderBy(person =>
{
var personObject = person as JObject;
var propertyValueObject = personObject.GetValue(parameterName) as JValue;
return propertyValueObject.Value;
})
.ToList();
Although it works I would prefer UPDATE #1 solution. :)
Here is an implementation with custom comparer. This allows you to pass any property name:
public class JObjComp<T> : IComparer<T>
{
private string _field;
public JObjComp(string field)
{
_field = field;
}
int IComparer<T>.Compare(T a, T b)
{
//this is bit flimsy but as we know that passed object is
//a dynamic, should work
dynamic aa=(dynamic)a;
dynamic bb=(dynamic)b;
return string.Compare(aa[_field].ToString(), bb[_field].ToString());
}
}
Now use our custom comparer:
List<dynamic> jObjList = JsonConvert.DeserializeObject<List<dynamic>>(jstr);
jObjList.Sort(new JObjComp<dynamic>(field));
The list is sorted insitu, so you can assert using jObjList itself.

Keep old values if not present in the json when deserialize

I have such a class:
public class item
{
public string Name { get; set; }
public string City { get; set; }
public string Pw { get; set; }
}
from which I create several objects I store in the DB. Then I want to update one of them with data coming from client in the form of a json like this:
{
"Name":"John",
"City":"NYC"
}
the idea would be to use:
item myitem = JsonConvert.DeserializeObject<item>(jsoncomingfromclient);
but doing so Pw is overwritten with null (while obviously I want to keep the original value)
NullValueHandling looks like a good candidate but it works if the value is null, in my case it is completely missing from the json.
Any idea how to deserialize a json keeping the old value in the destination object if the value is missing in the json?
Use JsonConvert.PopulateObject. It's designed for this purpose:
var item = new item { Name = "my name", City = "my city", Pw = "my pw" };
var json = #"
{
""Name"":""John"",
""City"":""NYC""
}";
JsonConvert.PopulateObject(json, item);
Debug.Assert(item.Pw == "my pw"); // no assert
Debug.Assert(item.Name == "John"); // no assert
Debug.Assert(item.City == "NYC"); // no assert
This part of code JsonConvert.DeserializeObject<item>(jsoncomingfromclient); will create new instance of type item based on parameter jsoncomingfromclient and return it.
This part item myitem = ... declares a variable myitem of type item and gives it a concrete instance. So there is no way to merge anything like this.
You just have to write some merge method manually and define what and how is merged between two objects.
Something like that
item dbitem = ...
item myitem = JsonConvert.DeserializeObject<item>(jsoncomingfromclient);
item mergedItem = myitem.merge(dbitem)

Categories