I am working on a JSON driven project and I would like to provide the SessionManager object with a dynamic list of permissionst. While I can work with an array of key value pairs for permissions, I was wondering if I could remove the property names so that the key is the Permission value and the value is the IsAllowed value.
public class SessionPermission
{
public string Permission { get; set; }
public bool IsAllowed { get; set; }
}
public class SessionManager
{
public string UserName { get; set; }
public string Password { get; set; }
public List<SessionPermission> Permissions { get; set; }
public void SetPermissions()
{
Permissions = new List<SessionPermission>
{
new SessionPermission {Permission = "CreateUsers", IsAllowed = false},
new SessionPermission {Permission = "EditUsers", IsAllowed = false},
new SessionPermission {Permission = "EditBlog", IsAllowed = true}
};
}
}
When I generate JSON it outputs an array of permissions:
{
"Permission": "CreateUsers",
"IsAllowed": false
},
I would like to know how to override the serialization so that it uses the values instead of the property names.
{
"CreateUsers": false
},
You could use the following custom converter:
public class SessionPermissionConverter : JsonConverter
{
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
var obj = (JObject)JObject.ReadFrom(reader);
JProperty property = obj.Properties().FirstOrDefault();
return new SessionPermission
{
Permission = property.Name,
IsAllowed = property.Value.Value<bool>()
};
}
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
SessionPermission permission = (SessionPermission)value;
JObject obj = new JObject();
obj[permission.Permission] = permission.IsAllowed;
obj.WriteTo(writer);
}
public override bool CanConvert(Type t)
{
return typeof(SessionPermission).IsAssignableFrom(t);
}
public override bool CanRead
{
get { return true; }
}
}
Usage:
var manager = new SessionManager();
manager.SetPermissions();
string json = JsonConvert.SerializeObject(manager, new SessionPermissionConverter());
Sample JSON:
{
"UserName": null,
"Password": null,
"Permissions": [
{
"CreateUsers": false
},
{
"EditUsers": false
},
{
"EditBlog": true
}
]
}
It should work fine going the opposite way as well.
Example: https://dotnetfiddle.net/mfbnuk
Related
This question already has answers here:
How to handle both a single item and an array for the same property using JSON.net
(9 answers)
Closed 3 years ago.
I am trying to process an object that can be either an array of object or just the object. Using the code below only works when the naics is an object and not an array. What am I doing wrong?
Here is the shortest example I can come up with:
[{
"section": "52.219-1.b",
"naics": [{
"naicsName": "Engineering Services",
"isPrimary": true,
"ExcpCounter": 1,
"isSmallBusiness": "Y",
"naicsCode": 541330
},
{
"naicsName": "Military and Aerospace Equipment and Military Weapons",
"isPrimary": true,
"ExcpCounter": 2,
"isSmallBusiness": "Y",
"naicsCode": 541330
}
]
},
{
"section": "52.219-1.b",
"naics": {
"naicsName": "Janitorial Services",
"isPrimary": true,
"isSmallBusiness": "Y",
"naicsCode": 561720
}
}
]
I will only have one of the types but I forced two in an array to force it into Quick Type.
My classes are:
[JsonProperty("naics", NullValueHandling = NullValueHandling.Ignore)]
public AnswerNaics Naics { get; set; }
public partial struct AnswerNaics
{
public AnswerNaic Naic;
public AnswerNaic[] NaicArray;
public static implicit operator AnswerNaics(AnswerNaic Naic) => new AnswerNaics { Naic = Naic };
public static implicit operator AnswerNaics(AnswerNaic[] NaicArray) => new AnswerNaics { NaicArray = NaicArray };
}
public partial class AnswerNaic
{
[JsonProperty("naicsName")]
public string NaicsName { get; set; }
[JsonProperty("hasSizeChanged")]
public string HasSizeChanged { get; set; }
[JsonProperty("isPrimary")]
public bool IsPrimary { get; set; }
[JsonProperty("ExcpCounter", NullValueHandling = NullValueHandling.Ignore)]
public long? ExcpCounter { get; set; }
[JsonProperty("isSmallBusiness")]
public string IsSmallBusiness { get; set; }
[JsonProperty("naicsCode")]
public string NaicsCode { get; set; }
}
internal class NaicsConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(AnswerNaics) || t == typeof(AnswerNaics?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.StartObject:
var objectValue = serializer.Deserialize<AnswerNaic>(reader);
return new AnswerNaics { Naic = objectValue };
case JsonToken.StartArray:
var arrayValue = serializer.Deserialize<AnswerNaic[]>(reader);
return new AnswerNaics { NaicArray = arrayValue };
}
throw new Exception("Cannot unmarshal type AnswerNaics");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (AnswerNaics)untypedValue;
if (value.NaicArray != null)
{
serializer.Serialize(writer, value.NaicArray);
return;
}
if (value.Naic != null)
{
serializer.Serialize(writer, value.Naic);
return;
}
throw new Exception("Cannot marshal type Naics");
}
public static readonly NaicsConverter Singleton = new NaicsConverter();
}
I have more object or array nodes, but I am just trying to figure out one to be able to apply to all of them.
Since you cannot change the incoming JSON, you're going to need a custom converter instead. Something like this for example:
public class NaicsConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(Naics);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
var naics = new Naics();
switch (reader.TokenType)
{
case JsonToken.StartObject:
// We know this is an object, so serialise a single Naics
naics.Add(serializer.Deserialize<Naic>(reader));
break;
case JsonToken.StartArray:
// We know this is an object, so serialise multiple Naics
foreach(var naic in serializer.Deserialize<List<Naic>>(reader))
{
naics.Add(naic);
}
break;
}
return naics;
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And the supporting classes:
public class Root
{
public string Section { get; set; }
[JsonConverter(typeof(NaicsConverter))]
public Naics Naics { get; set; }
}
// This isn't ideal, but it's quick and dirty and should get you started
public class Naics : List<Naic>
{
}
public class Naic
{
public string NaicsName { get; set; }
public bool IsPrimary { get; set; }
public string IsSmallBusiness { get; set; }
public long NaicsCode { get; set; }
}
And finally, to deserialise:
var settings = new JsonSerializerSettings {Converters = {new NaicsConverter()}};
var root = JsonConvert.DeserializeObject<Root[]>(Json, settings);
Now your object will get serialised into the list, but as a single item.
You can solve this using a dynamic field in your class.
Consider this JSON:
[
{
"field1": "val1",
"nested": [
{
"nestedField": "val2"
},
{
"nestedField": "val3"
}
]
},
{
"field1": "val4",
"nested":
{
"nestedField": "val5"
}
}
]
nested field is first an array with 2 objects and in the second appearance a single object. (similar to the JSON you posted)
So the class representation would look like:
public class RootObject
{
public string field1 { get; set; }
public dynamic nested { get; set; }
public List<NestedObject> NestedObjects
{
get
{
if(nested is JArray)
{
return JsonConvert.DeserializeObject<List<NestedObject>>(nested.ToString());
}
var obj = JsonConvert.DeserializeObject<NestedObject>(nested.ToString());
return new List<NestedObject> { obj };
}
}
}
public class NestedObject
{
public string nestedField { get; set; }
}
The Deserialization code is trivial using Newtonsoft JSON:
var objectList = JsonConvert.DeserializeObject<List<RootObject>>("some_json");
foreach(var v in objectList)
{
foreach(var n in v.NestedObjects)
{
Console.WriteLine(n.nestedField);
}
}
The only change is an implementation of NestedObjects ready only property. It check if the dynamic object is JArray or object. In any case, it returns a List of nested objects.
I am trying to convert List to json. Structure is as follow:
public class ResourceCollection
{
public string Name { get; set; }
public Resources Resources { get; set;}
}
public class Resources
{
public string en { get; set; }
}
List<ResourceCollection> liResourceName = new List<ResourceCollection>();
//section to add the objects in list
string json = JsonConvert.SerializeObject(liResourceName, Newtonsoft.Json.Formatting.Indented);
This is producing the result as expected:
[
{
"Name": "Hello",
"Resources":
{
"en": "Hello"
}
},
{
"Name": "World",
"Resources":
{
"en": "World"
}
}
]
How can I get the results like:-
{
"Hello": {
"en": "Hello"
},
"World": {
"en": "World"
}
}
You will need to create a custom JsonConverter that knows how to handle serializing ResourceCollection
public class ResourceCollectionConverter : JsonConverter<List<ResourceCollection>> {
public override bool CanRead {
get {
return false; //because ReadJson is not implemented
}
}
public override List<ResourceCollection> ReadJson(JsonReader reader, Type objectType, List<ResourceCollection> existingValue, bool hasExistingValue, JsonSerializer serializer) {
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, List<ResourceCollection> value, JsonSerializer serializer) {
var obj = new JObject(); // { }
foreach (var item in value) {
//{ "Hello" : { "en": "Hello" } }
obj[item.Name] = JObject.FromObject(item.Resources);
}
obj.WriteTo(writer);
}
}
Use the converter so that JsonConvert knows how to handle the serialization.
For example
List<ResourceCollection> liResourceName = new List<ResourceCollection>();
liResourceName.Add(new ResourceCollection { Name = "Hello", Resources = new Resources { en = "Hello" } });
liResourceName.Add(new ResourceCollection { Name = "World", Resources = new Resources { en = "World" } });
var formating = Newtonsoft.Json.Formatting.Indented;
var converter = new ResourceCollectionConverter();
string json = JsonConvert.SerializeObject(liResourceName, formating , converter);
Lets say I have the below json.
{
"allitemscount":2,
"allitems":[
{"itemid":"1","itemname":"one"},
{"itemid":"2","itemname":"two"}],
"customitems":[
{"itemid":"3","itemname":"three"},
{"itemid":"4","itemname":"four"}]
}
and when deserializing this json, it should go to the below C# model.
public class response
{
public int allitemscount;
public List<item> items;
}
public class item
{
public string itemid;
public string itemname;
}
Question:
How to switch between allitems and customitems based on a condition? For eg., if useAllitems is true, allitems from the json to be filled in items and if useCustomItems is true, customitems to be filled in items property. Please help on how to do this.
Using JsonProperty on public List<item> items is allowing to switch between either allitems, but is there a way to deserialize based on the above mentioned condition.
I made it with writing our own ItemConverter which inherited from JsonConverter,
Sample model json that I use in my trying:
{
"allitemscount": 2,
"UseCustomItems": true,
"allitems": [
{
"itemid": "1",
"itemname": "one"
},
{
"itemid": "2",
"itemname": "two"
}
],
"customitems": [
{
"itemid": "3",
"itemname": "three"
},
{
"itemid": "4",
"itemname": "four"
}
]
}
Console application's main method:
static void Main(string[] args)
{
using (StreamReader r = new StreamReader(#"\model.json")) // json path
{
string json = r.ReadToEnd();
var deserializedJson = JsonConvert.DeserializeObject<Result>(json, new ItemConverter());
}
}
Models:
public class Result // main object
{
[JsonProperty("allitemscount")]
public long Allitemscount { get; set; }
public bool UseCustomItems { get; set; }
}
public class ResultA : Result // CustomItems Model
{
[JsonProperty("customitems")]
private List<Item> Items { get; set; }
}
public class ResultB : Result // AllItems Model
{
[JsonProperty("allitems")]
private List<Item> Items { get; set; }
}
public class Item
{
[JsonProperty("itemid")]
public string Itemid { get; set; }
[JsonProperty("itemname")]
public string Itemname { get; set; }
}
And the ItemConverter that we used while deserializing to object:
internal class ItemConverter : JsonConverter
{
private Type currentType;
public override bool CanConvert(Type objectType)
{
return typeof(Item).IsAssignableFrom(objectType) || objectType == typeof(Result);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
if (item["UseCustomItems"] != null)
{
// save the type for later.
switch (item["UseCustomItems"].Value<bool>())
{
case true:
currentType = typeof(ResultA);
return item.ToObject<ResultA>(); // return result as customitems result
case false:
currentType = typeof(ResultB);
return item.ToObject<ResultB>(); // return result as allitems result
}
return item.ToObject<Result>();
}
// use the last type you read to serialise.
return item.ToObject(currentType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
The result should be like bellowing image
I hope this solution help to you
You can deserialize above json by changing your response class as follows,
public class response{
public int allitemscount;
public List<item> allitems;
public List<item> customitems;
}
then use the following code,
var jsonData = "{\"allitemscount\":2, \"allitems\":[{\"itemid\":\"1\",\"itemname\":\"one\"}, {\"itemid\":\"2\",\"itemname\":\"two\"}],\"customitems\":[{\"itemid\":\"3\",\"itemname\":\"three\"},{\"itemid\":\"4\",\"itemname\":\"four\"}]}";
var data = JsonConvert.DeserializeObject<response>(jsonData);
foreach(var str in data.allitems) {
Console.WriteLine(str.itemid +'-'+str.itemname);
}
foreach(var str in data.customitems) {
Console.WriteLine(str.itemid +'-'+str.itemname);
}
I am trying to deserialize an Object like this.
My issue is that it is blowing up trying to deserialize the inner items.
{
"outeritems": [{
"inneritems": [
[{
"itemid": "1"
}, {
"itemid": "2"
}]
]
}]
}
I have already tried
public List<List<inneritems>> inneritems{ get; set; }
also
public List<inneritems> inneritems{ get; set; }
I'm thinking this might have to have a custom JSON converter
Actually vikas is close in anwering your question.
public class Outeritem
{
public List<List<object>> inneritems { get; set; }
}
public class RootValue
{
public List<Outeritem> outeritems { get; set; }
}
[TestMethod]
public void SerializeAndDeserializeTest()
{
var expected = "{\"outeritems\":[{\"inneritems\":[[{\"itemid\":\"1\"},{\"itemid\":\"2\"}]]}]}";
var rootValue = new RootValue
{
outeritems = new List<Outeritem>
{
new Outeritem
{
inneritems = new List<List<object>> {
new List<object> { new {itemid = "1"},new {itemid = "2"} }
}
}
}
};
var actual = JsonConvert.SerializeObject(rootValue);
Assert.AreEqual(expected, actual);
}
Try this
public class Inneritem
{
public String itemid { get; set; }
}
public class Outeritem
{
public List<Inneritem> inneritems { get; set; }
}
public class RootValue
{
public List<Outeritem> outeritems { get; set; }
}
I had to create a custom Newtonsoft JSON Converter
This is what I did.
Created A JsonCreationConverter Base Class
public abstract class JsonCreationConverter<T> : JsonConverter
{
protected abstract T Create(Type objectType, JObject jObject);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanWrite is false. The type will skip the converter.");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
JObject jObject = JObject.Load(reader);
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override bool CanWrite
{
get { return false; }
}
}
Created A Costume Converter that inherited my base class
public class OuterConverter :
JsonCreationConverter<OuterItems>
{
protected override OuterItems Create(Type objectType, JObject jObject)
{
OuterItems outeritems =
new OuterItems();
var properties = jObject.Properties().ToList();
outeritems.InnerItems = GetInnerItems((object)properties[0].Value);
return outeritems;
}
// Need to iterate through list so creating a custom object
private List<List<InnerItems>> GetInnerItems(object propertyValue)
{
string sinneritems = "";
object inneritems = propertyValue;
sinneritems = String.Format("{0}", inneritems);
sinneritems = sinneritems.Insert(1, "{ \"Items\": [");
sinneritems = sinneritems.Substring(1, sinneritems.Length - 1);
sinneritems = sinneritems.Remove(sinneritems.Length - 1);
sinneritems += "]}";
dynamic results = JObject.Parse(sinneritems);
List<List<InnerItems>> innerItemsList = new List<List<InnerItems>>();
List<InnerItems> linnerItems = new List<InnerItems>();
foreach (var items in results.Items)
{
foreach (var item in items)
{
string sItem = String.Format("{0}", item);
InnerItems ninneritems = Newtonsoft.Json.JsonConvert.DeserializeObject<InnerItems>(sItem);
linnerItems.Add(ninneritems);
}
innerItemsList.Add(linnerItems);
}
return innerItemsList;
}
}
Append the New Converter on the Newtonsoft Deserializer
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result.ToString(),
new OuterConverter());
This question already has an answer here:
Json.NET case-sensitive deserialization
(1 answer)
Closed 6 years ago.
I am trying to deserialize a string content into an object, but I want the content to be case sensitive. The code should only succeed if the string has lower case properties and fail if it has upper case properties. Following is the class:
internal class ResponseList
{
[DataMember]
[JsonProperty]
internal List<Response> Value { get; set; }
}
internal class Response
{
[DataMember]
[JsonProperty]
internal string Id { get; set; }
[DataMember]
[JsonProperty]
internal string Location { get; set; }
[DataMember]
[JsonProperty]
internal PlanClass Plan { get; set; }
}
internal class PlanClass
{
[DataMember]
[JsonProperty]
internal string Name { get; set; }
[DataMember]
[JsonProperty]
internal string Product { get; set; }
[DataMember]
[JsonProperty]
internal string Publisher { get; set; }
}
Following is the code I have. But this is not case-sensitive. It is succeeding for both upper and lowercase:
string content = File.ReadAllText(contentFilePath);
JsonSerializerSettings jsonSerializerSettings1 = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
ResponseList response = (ResponseList)JsonConvert.DeserializeObject(contentResourceOutput, typeof(ResponseList), Constants.JsonSerializerSettings);
The code should only succeed if the content is:
{
"value": [
{
"id": "id1",
"location": "location1",
"plan": {
"name": "free",
"product": "product1",
"publisher": "publisher1"
}
}
]
}
and fail if even if one of the keys is uppercase. E.g.
{
"value": [
{
"Id": "id1",
"Location": "location1",
"plan": {
"Name": "free",
"product": "product1",
"publisher": "publisher1"
}
}
]
}
Notice that only the Keys/Property names should be lower case. The values can be upper case.
Is there a way to make JsonConvert.Deserializeobject case sensitive?
You can write a custom converter to handle this use case. In regards to your need for a recursive inspection of all key names, I used the fantastic WalkNode answer given by Thymine here.
var json = #"{""id"": ""id1"",""name"": ""name1"",""type"": ""type1""}";
var json2 = #"{""id"": ""id1"",""Name"": ""name1"",""type"": ""type1""}";
JsonSerializerSettings settings = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = new List<JsonConverter> { new CamelCaseOnlyConverter() }
};
var response = JsonConvert.DeserializeObject<Response>(json, settings);
var response2 = JsonConvert.DeserializeObject<Response>(json2, settings);
public class CamelCaseOnlyConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = (JObject)JToken.Load(reader);
var isCamelCased = true;
WalkNode(token, null,
t =>
{
var nameFirstChar = t.Name[0].ToString();
if (!nameFirstChar.Equals(nameFirstChar.ToLower(),
StringComparison.CurrentCulture))
{
isCamelCased = false;
return;
}
});
if (!isCamelCased) return null;
return token.ToObject(objectType);
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
JObject o = (JObject)JToken.FromObject(value);
o.WriteTo(writer);
}
private static void WalkNode(JToken node,
Action<JObject> objectAction = null,
Action<JProperty> propertyAction = null)
{
if (node.Type == JTokenType.Object)
{
if (objectAction != null) objectAction((JObject)node);
foreach (JProperty child in node.Children<JProperty>())
{
if (propertyAction != null) propertyAction(child);
WalkNode(child.Value, objectAction, propertyAction);
}
}
else if (node.Type == JTokenType.Array)
foreach (JToken child in node.Children())
WalkNode(child, objectAction, propertyAction);
}
}
The first string will return a hydrated object. The second string will terminate early, returning null.