I'm working on a C# program for JSON serialisation.
My object looks as follows (example of a property):
public class Device
{
[JsonProperty("ALLTYPES_NAME")]
public string ALLTYPES_NAME { get; set; }
[JsonProperty("INFORMATION")]
public string INFORMATION { get; set; }
...
Now I have the following information (in a textfile):
ALLTYPES_NAME "Object1"
ALLTYPES_NAME "Object2"
INFORMATION "Inside_Info"
I would like to create two objects, which are to be JSON serialised as follows:
"desired_objects": [
{
"ALLTYPES_NAME": "Object1",
},
{
"ALLTYPES_NAME": "Object2",
"INFORMATION": "Inside_Info,
...
In order to get this done, I need something like:
temp_obj.GetPropertyByName("ALLTYPES_NAME") = "Object1";
desired_objects.Add(temp_obj);
...
temp_obj.GetPropertyByName("ALLTYPES_NAME") = "Object2";
temp_obj.GetPropertyByName("INFORMATION") = "Inside_Information";
...
One way to do this, is working with templates. However I wonder if this is needed, seen the fact that the needed information is retrievable using the [JsonProperty] directives, hence my question:
Does a method .GetPropertyByName() exist, based on the [JsonProperty ...]? (Or even larger, can the [JsonProperty] directives be used for something else rather than the JSON serialiser?)
You can use Json.NET's IContractResolver to get a JsonObjectContract for your Device object that contains information about all the properties of the type including their JSON names and get/set methods. The following extension method does the trick:
public static partial class JsonExtensions
{
static readonly IContractResolver defaultResolver = JsonSerializer.CreateDefault().ContractResolver;
public static void SetJsonProperty<T>(T obj, string jsonName, object value, bool exact = false, IContractResolver resolver = null)
{
if (!TrySetJsonProperty(obj, jsonName, value, exact, resolver))
throw new ArgumentException(string.Format("Could not set property {0} in {1}.", jsonName, obj));
}
public static bool TrySetJsonProperty<T>(T obj, string jsonName, object value, bool exact = false, IContractResolver resolver = null)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
resolver = resolver ?? defaultResolver;
var contract = resolver.ResolveContract(obj.GetType()) as JsonObjectContract;
if (contract == null)
return false;
var property = contract.Properties.GetProperty(jsonName, exact ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
if (property == null || !property.Writable)
return false;
property.ValueProvider.SetValue(obj, value);
return true;
}
}
Furthermore, if you are reading from a text file and some of your property value types are not strings, you will need to convert the textual values from the file to the appropriate .Net type. The following does that:
public static partial class JsonExtensions
{
public static void SetConvertibleJsonProperty<T, TConvertible>(T obj, string jsonName, TConvertible value, bool exact = false, IContractResolver resolver = null) where TConvertible : IConvertible
{
if (!TrySetConvertibleJsonProperty(obj, jsonName, value, exact, resolver))
throw new ArgumentException(string.Format("Could not set property {0} in {1}.", jsonName, obj));
}
public static bool TrySetConvertibleJsonProperty<T, TConvertible>(T obj, string jsonName, TConvertible value, bool exact = false, IContractResolver resolver = null)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
resolver = resolver ?? defaultResolver;
var contract = resolver.ResolveContract(obj.GetType()) as JsonObjectContract;
if (contract == null)
return false;
var property = contract.Properties.GetProperty(jsonName, exact ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
if (property == null || !property.Writable)
return false;
var finalValue = value == null ? null : Convert.ChangeType(value, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType, CultureInfo.InvariantCulture);
property.ValueProvider.SetValue(obj, finalValue);
return true;
}
}
And to use it, do:
JsonExtensions.SetConvertibleJsonProperty(temp_obj, "ALLTYPES_NAME", "Object1");
JsonExtensions.SetConvertibleJsonProperty(temp_obj, "ALLTYPES_NAME", "Object2");
JsonExtensions.SetConvertibleJsonProperty(temp_obj, "INFORMATION", "Inside_Information");
// The following sets the following property
// [JsonProperty("DECIMAL_DATA")]
// public decimal DecimalInformation { get; set; }
JsonExtensions.SetConvertibleJsonProperty(temp_obj, "DECIMAL_DATA", "3.1111");
Notes:
If you serialize and deserialize using camel case, pass CamelCasePropertyNamesContractResolver for the IContractResolver resolver parameter.
The method is not designed to work for dynamic objects or dictionaries.
For an equivalent method to get a property value by JSON property name, see this answer to How to get Json Property name using reflection in C#.
Demo fiddle here.
After some experiments, based on the comments of Jon Skeet, I realise that I don't even need the JSON directives for this, as you can see from following code excerpt:
System.Reflection.PropertyInfo[] list_of_attributes =
(new Own_Class()).GetType().GetProperties();
string[] list_of_attribute_names = new string[list_of_attributes.Length];
for (int i = 0; i< list_of_attributes.Length; i++)
list_of_attribute_names[i] = list_of_attributes[i].Name;
combobox_on_form.Items.AddRange(list_of_attribute_names);
I am trying to remove a property within a Microsoft.graph User object.
I am currently using the "Property.Remove()" method. First, I am setting the User object to a deserialized JObject.
The way I am doing this is serializing the User object into a Json string (jsonString) and deserializing jsonString (jsonStringUpdated). Afterwards, I am calling jsonStringUpdated.property("____") .Remove();
Is there a simpler way to do this? Below is an example:
{
string jsonString = JsonConvert.SerializeObject(user);
var jsonStringUpdated = (JObject)JsonConvert.DeserializeObject(jsonString);
jsonStringUpdated.Property("country").Remove();
}
I would not say that this is simpler option, but I would say that it is better one (in terms of reusability, flexibility and possibly performance). You can create custom contract resolver:
// generic type parameter can be omitted with hardcoding typeof
// handling for multiple properties can be added
public class IgnorePropertyResolver<T> : DefaultContractResolver
{
private readonly string _propName;
public IgnorePropertyResolver(string propName)
{
_propName = propName;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (typeof(T).IsAssignableFrom(member.DeclaringType) && member.Name == _propName)
{
property.ShouldSerialize = o => false;
}
return property;
}
}
And usage:
class MyClass
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
var serializeObject = JsonConvert.SerializeObject(new MyClass(),
new JsonSerializerSettings
{
ContractResolver = new IgnorePropertyResolver<MyClass>(nameof(MyClass.Prop2))
});
Console.WriteLine(serializeObject); // prints {"Prop1":0}
I have an object that needs to be serialized in such a way that both null and "whitespace" (empty or just spaces) values are not serialized. I don't control the object itself and therefore can't set attributes, but I know that all the properties are strings. Setting NullValueHandling to Ignore obviously only gets me part of the way to the solution.
It "seems" (as best I understand) like what I need to do is create a custom DefaultContractResolver but I haven't come up with a solution that works. Here are a couple failed attempts, for reference, that throw no exceptions but have no obvious effect on the serialization either:
public class NoNullWhiteSpaceResolver : DefaultContractResolver
{
public static readonly NoNullWhiteSpaceResolver Instance = new NoNullWhiteSpaceResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
/* this doesn't work either
if (property.ValueProvider.GetValue(member) == null ||
(property.PropertyType == typeof(string) &&
string.IsNullOrWhiteSpace((string)property.ValueProvider.GetValue(member))))
{
property.ShouldSerialize = i => false;
}*/
if (property.PropertyType == typeof(string))
{
property.ShouldSerialize =
instance =>
{
try
{
string s = (string) instance;
bool shouldSkip = string.IsNullOrWhiteSpace(s);
return !string.IsNullOrWhiteSpace(s);
}
catch
{
return true;
}
};
}
return property;
}
}
I'm implementing the resolver by
string str = JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
Formatting = Formatting.None;
ContractResolver = new NoNullWhiteSpaceResolver();
});
Maybe I'm going about this backward but I appreciate any insights people have. I've worked around the issue by using an extension method/reflection to iterate over the properties of the object and setting the value to null if it's "nullorwhitespace" and then using the standard NullValueHandling but I'm hoping I can find a way to configure all of this in the serialization.
This seems to work:
public class NoNullWhiteSpaceResolver : DefaultContractResolver {
public static readonly NoNullWhiteSpaceResolver Instance = new NoNullWhiteSpaceResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType == typeof(string)) {
property.ShouldSerialize =
instance => {
try {
var rawValue = property.ValueProvider.GetValue(instance);
if (rawValue == null) {
return false;
}
string stringValue = property.ValueProvider.GetValue(instance).ToString();
return !string.IsNullOrWhiteSpace(stringValue);
}
catch {
return true;
}
};
}
return property;
}
}
Using this test class:
public class TestClass {
public string WhiteSpace => " ";
public string Null = null;
public string Empty = string.Empty;
public string Value = "value";
}
This is the output:
{"Value":"value"}
A)
I have a DLL library include a class like the bellow code:
public class Thing
{
// OTHER_PROPERTIES
//..........................
[JsonProperty(Required = Required.Always)]
public bool IsBook { get; set; }
}
Assumption: I have not access to the source of the Thing class.
B)
And I have a JSON like this:
{
OTHER_PROPERTIES
}
Note: It has not a pair of name-value for IsBook
Assumption: I wont change the JSON to include IsBook in it.
C)
If I run JsonConvert.DeserializeObject<Thing>(json); then I get the following error:
Error: Required property not found in json ....
Question:
How can I write a custom code to solve the above error by observing the assumptions of the problem?
(please read the above assumptions again before writing your answer.)
You can use custom contract resolver to achieve that. For example:
public class Thing
{
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty(Required = Required.Always)]
public bool IsBook { get; set; }
}
class NeverRequiredContractResolver : DefaultContractResolver {
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
var prop = base.CreateProperty(member, memberSerialization);
prop.Required = Required.Default;
return prop;
}
}
And then:
var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}",
new JsonSerializerSettings {
ContractResolver = new NeverRequiredContractResolver()
});
Of course you can assign resolver globally and not pass it to every DeserializeObject:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
ContractResolver = new NeverRequiredContractResolver()
};
var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}");
you can make only specific properties of specific classes non-required (and not all of them like in example above):
class CustomPropertyContractResolver : DefaultContractResolver {
private readonly Action<MemberInfo, JsonProperty> _propFixup;
public CustomPropertyContractResolver(Action<MemberInfo, JsonProperty> propFixup) {
_propFixup = propFixup;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
var prop = base.CreateProperty(member, memberSerialization);
_propFixup?.Invoke(member , prop);
return prop;
}
}
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
ContractResolver = new CustomPropertyContractResolver((member, prop) => {
if (member.DeclaringType == typeof(Thing) && member.Name == "IsBook") {
prop.Required = Required.Default;
}
})
};
var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}");
and overall adjust example above however you wish for your specific use case.
Is there a way to specify the order of fields in a serialized JSON object using JSON.NET?
It would be sufficient to specify that a single field always appear first.
The supported way is to use the JsonProperty attribute on the class properties that you want to set the order for. Read the JsonPropertyAttribute order documentation for more information.
Pass the JsonProperty an Order value and the serializer will take care of the rest.
[JsonProperty(Order = 1)]
This is very similar to the
DataMember(Order = 1)
of the System.Runtime.Serialization days.
Here is an important note from #kevin-babcock
... setting the order to 1 will only work if you set an order greater than 1 on all other properties. By default any property without an Order setting will be given an order of -1. So you must either give all serialized properties and order, or set your first item to -2
You can actually control the order by implementing IContractResolver or overriding the DefaultContractResolver's CreateProperties method.
Here's an example of my simple implementation of IContractResolver which orders the properties alphabetically:
public class OrderedContractResolver : DefaultContractResolver
{
protected override System.Collections.Generic.IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
}
}
And then set the settings and serialize the object, and the JSON fields will be in alphabetical order:
var settings = new JsonSerializerSettings()
{
ContractResolver = new OrderedContractResolver()
};
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
In my case Mattias' answer didn't work. The CreateProperties method was never called.
After some debugging of Newtonsoft.Json internals, I came up with another solution.
public class JsonUtility
{
public static string NormalizeJsonString(string json)
{
// Parse json string into JObject.
var parsedObject = JObject.Parse(json);
// Sort properties of JObject.
var normalizedObject = SortPropertiesAlphabetically(parsedObject);
// Serialize JObject .
return JsonConvert.SerializeObject(normalizedObject);
}
private static JObject SortPropertiesAlphabetically(JObject original)
{
var result = new JObject();
foreach (var property in original.Properties().ToList().OrderBy(p => p.Name))
{
var value = property.Value as JObject;
if (value != null)
{
value = SortPropertiesAlphabetically(value);
result.Add(property.Name, value);
}
else
{
result.Add(property.Name, property.Value);
}
}
return result;
}
}
In my case niaher's solution did not work because it didn't handle objects in arrays.
Based on his solution this is what I came up with
public static class JsonUtility
{
public static string NormalizeJsonString(string json)
{
JToken parsed = JToken.Parse(json);
JToken normalized = NormalizeToken(parsed);
return JsonConvert.SerializeObject(normalized);
}
private static JToken NormalizeToken(JToken token)
{
JObject o;
JArray array;
if ((o = token as JObject) != null)
{
List<JProperty> orderedProperties = new List<JProperty>(o.Properties());
orderedProperties.Sort(delegate(JProperty x, JProperty y) { return x.Name.CompareTo(y.Name); });
JObject normalized = new JObject();
foreach (JProperty property in orderedProperties)
{
normalized.Add(property.Name, NormalizeToken(property.Value));
}
return normalized;
}
else if ((array = token as JArray) != null)
{
for (int i = 0; i < array.Count; i++)
{
array[i] = NormalizeToken(array[i]);
}
return array;
}
else
{
return token;
}
}
}
This will work for normal classes, dictionaries and ExpandoObject (dynamic object) as well.
class OrderedPropertiesContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
{
var props = base.CreateProperties(type, memberSerialization);
return props.OrderBy(p => p.PropertyName).ToList();
}
}
class OrderedExpandoPropertiesConverter : ExpandoObjectConverter
{
public override bool CanWrite
{
get { return true; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var expando = (IDictionary<string, object>)value;
var orderedDictionary = expando.OrderBy(x => x.Key).ToDictionary(t => t.Key, t => t.Value);
serializer.Serialize(writer, orderedDictionary);
}
}
var settings = new JsonSerializerSettings
{
ContractResolver = new OrderedPropertiesContractResolver(),
Converters = { new OrderedExpandoPropertiesConverter() }
};
var serializedString = JsonConvert.SerializeObject(obj, settings);
If you just want to pull a single attribute up to the front without thinking about the perhaps unintuitive number system, just use int.MinValue.
[JsonProperty(Order = int.MinValue)]
As Charlie noted, you can somewhat control the ordering of the JSON properties by ordering the properties in the class itself. Unfortunately, this approach doesn't work for properties inherited from a base class. The base class properties will be ordered as they are laid out in code, but will appear before the base class properties.
And for anyone wondering why you might want to alphabetize JSON properties, it's a whole lot easier to work with raw JSON files, particularly for classes with lots of properties, if they are ordered.
If you don't want to put a JsonProperty Order attribute on every class property, then its very simple to make your own ContractResolver...
The IContractResolver interface provides a way to customize how the JsonSerializer serializes and deserializes .NET objects to JSON without placing attributes on your classes.
Like this:
private class SortedPropertiesContractResolver : DefaultContractResolver
{
// use a static instance for optimal performance
static SortedPropertiesContractResolver instance;
static SortedPropertiesContractResolver() { instance = new SortedPropertiesContractResolver(); }
public static SortedPropertiesContractResolver Instance { get { return instance; } }
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
if (properties != null)
return properties.OrderBy(p => p.UnderlyingName).ToList();
return properties;
}
}
Implement:
var settings = new JsonSerializerSettings { ContractResolver = SortedPropertiesContractResolver.Instance };
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
Actually, since my Object was already a JObject, I used the following solution:
public class SortedJObject : JObject
{
public SortedJObject(JObject other)
{
var pairs = new List<KeyValuePair<string, JToken>>();
foreach (var pair in other)
{
pairs.Add(pair);
}
pairs.OrderBy(p => p.Key).ForEach(pair => this[pair.Key] = pair.Value);
}
}
and then use it like this:
string serializedObj = JsonConvert.SerializeObject(new SortedJObject(dataObject));
The following recursive method uses reflection to sort the internal token list on an existing JObject instance rather than creating a brand new sorted object graph. This code relies on internal Json.NET implementation details and should not be used in production.
void SortProperties(JToken token)
{
var obj = token as JObject;
if (obj != null)
{
var props = typeof (JObject)
.GetField("_properties",
BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(obj);
var items = typeof (Collection<JToken>)
.GetField("items", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(props);
ArrayList.Adapter((IList) items)
.Sort(new ComparisonComparer(
(x, y) =>
{
var xProp = x as JProperty;
var yProp = y as JProperty;
return xProp != null && yProp != null
? string.Compare(xProp.Name, yProp.Name)
: 0;
}));
}
foreach (var child in token.Children())
{
SortProperties(child);
}
}
If you control (i.e. write) the class, put the properties in alphabetical order and they will serialize in alphabetical order when JsonConvert.SerializeObject() is called.
I want to serialize an comblex object and keep the order of the properties as they where defined in code. I can't just add [JsonProperty(Order = 1)] because the class itself is out of my scope.
This solution also takes into account that properties which are defined in a base class should have a higher priority.
This may not be bulletproof, since nowhere is defined that the MetaDataAttribute ensures the correct order, but it seems to work. For my use case this is ok. since I only want to maintain human readability for an auto generated config file.
public class PersonWithAge : Person
{
public int Age { get; set; }
}
public class Person
{
public string Name { get; set; }
}
public string GetJson()
{
var thequeen = new PersonWithAge { Name = "Elisabeth", Age = Int32.MaxValue };
var settings = new JsonSerializerSettings()
{
ContractResolver = new MetadataTokenContractResolver(),
};
return JsonConvert.SerializeObject(
thequeen, Newtonsoft.Json.Formatting.Indented, settings
);
}
public class MetadataTokenContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(
Type type, MemberSerialization memberSerialization)
{
var props = type
.GetProperties(BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.NonPublic
).ToDictionary(k => k.Name, v =>
{
// first value: declaring type
var classIndex = 0;
var t = type;
while (t != v.DeclaringType)
{
classIndex++;
t = type.BaseType;
}
return Tuple.Create(classIndex, v.MetadataToken);
});
return base.CreateProperties(type, memberSerialization)
.OrderByDescending(p => props[p.PropertyName].Item1)
.ThenBy(p => props[p.PropertyName].Item1)
.ToList();
}
}
If you want to globally configure your API with ordered fields, please combine Mattias Nordberg answer:
public class OrderedContractResolver : DefaultContractResolver
{
protected override System.Collections.Generic.IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
}
}
with my answer here:
How to force ASP.NET Web API to always return JSON?
UPDATE
I just saw the downvotes. Please see the answer from 'Steve' below for how to do this.
ORIGINAL
I followed the JsonConvert.SerializeObject(key) method call via reflection (where key was an IList) and found that JsonSerializerInternalWriter.SerializeList gets called. It takes a list and loops through via
for (int i = 0; i < values.Count; i++) { ...
where values is the IList parameter brought in.
Short answer is...No, there's no built in way to set the order the fields are listed in the JSON string.
There's no order of fields in the JSON format so defining an order doesn't make sense.
{ id: 1, name: 'John' } is equivalent to { name: 'John', id: 1 } (both represent a strictly equivalent object instance)