Reputation: 1996
I would have my JSON string as below which needs to be deserialized to the below class
{
"Id":"1",
"Names":{
"string":"Surya"
},
"ClassTypes":{
"Types":[
{
"TypeId":"1",
"TypeName":"First Name"
},
{
"TypeId":"2",
"TypeName":"Last Name"
}
]
},
"Status":"1",
"DOB":"23/12/2014"
}
Class Definition
public class MyClass
{
public int Id { get; set; }
public IList<string> Names { get; protected set; }
public IList<Types> ClassTypes { get; protected set; }
public StatusType Status { get; set; }
public DateTime DOB { get; set; }
public MyClass()
{
Names = new List<string>();
ClassTypes = new List<Types>();
Status = StatusType.Active;
}
}
public class Types
{
public int TypeId { get; set; }
public string TypeName { get; set; }
}
public enum StatusType
{
Active = 0,
InActive = 1
}
I have used the following code for deserialization, but getting error
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = new IncludeNonPublicMembersContractResolver();
JsonConvert.DeserializeObject<MyClass>(jsonString, serializerSettings);
public class IncludeNonPublicMembersContractResolver : DefaultContractResolver
{
public IncludeNonPublicMembersContractResolver()
{
DefaultMembersSearchFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
}
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var members = base.GetSerializableMembers(objectType);
return members.Where(m => !m.Name.EndsWith("k__BackingField")).ToList();
}
}
Error Details
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IList`1[System.String]' 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 'Names.string', line 1, position 28.
Note - I can't change by JSON string and solution to be more generic has this would be required for other classes as well :(
Upvotes: 2
Views: 504
Reputation: 2220
One way is to use a JsonConverter:
public class MyClass
{
public int Id { get; set; }
[JsonProperty("Names"), JsonConverter(typeof(NamesConverter))]
public IList<string> Names { get; protected set; }
[JsonProperty("ClassTypes"), JsonConverter(typeof(TypesConverter))]
public IList<Types> ClassTypes { get; protected set; }
public StatusType Status { get; set; }
[JsonProperty("DOB"), JsonConverter(typeof(DateTimeConverter))]
public DateTime DOB { get; set; }
public MyClass()
{
Names = new List<string>();
ClassTypes = new List<Types>();
Status = StatusType.Active;
}
public override string ToString()
{
return
string.Format("ID: {0}\nNames:\n{1}\nClassTypes:\n{2}Status: {3}\nDOB: {4}",
Id, string.Join("\n", Names), string.Join("\n", ClassTypes), Status, DOB);
}
}
public class Types
{
public int TypeId { get; set; }
public string TypeName { get; set; }
public override string ToString()
{
return string.Format("\tTypeId: {0}\n\tTypeName: {1}\n", TypeId, TypeName);
}
}
public enum StatusType
{
Active = 0,
InActive = 1
}
class NamesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Dictionary<string, string>).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<Dictionary<string, string>>(reader).Values.ToList();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
class TypesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Dictionary<string,List<Types>>).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<Dictionary<string,List<Types>>>(reader)
.Values.First().ToList();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
class DateTimeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(string).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return DateTime.ParseExact(serializer.Deserialize<string>(reader), @"dd\/MM\/yyyy", null);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
...
var jsonobj = JsonConvert.DeserializeObject<MyClass>(json);
Console.WriteLine(jsonobj);
Print:
Names:
Surya
ClassTypes:
TypeId: 1
TypeName: First Name
TypeId: 2
TypeName: Last Name
Status: InActive
DOB: 12/23/2014 12:00:00 AM
https://dotnetfiddle.net/EfQuET
Two way - parse json, but then you need to change the access for the properties Names,ClassTypes or add the constructor:
var jObject = JObject.Parse(json);
var names = new List<string>
{
jObject["Names"].Value<string>("string")
};
var types = jObject["ClassTypes"]["Types"]
.Select(x => new Types
{
TypeId = x.Value<int>("TypeId"),
TypeName = x.Value<string>("TypeName")
})
.ToList();
var data = new MyClass(names,types)
{
Id = jObject.Value<int>("Id"),
Status = (StatusType)Enum.Parse(typeof(StatusType),jObject.Value<string>("Status")),
DOB = DateTime.ParseExact(jObject.Value<string>("DOB"), @"dd\/MM\/yyyy", null)
};
Console.WriteLine(data);
https://dotnetfiddle.net/HcPxT9
Upvotes: 2
Reputation: 24903
Names
is not an array, it's an object:
public class Names
{
public string @string { get; set; }
}
public class Type
{
public string TypeId { get; set; }
public string TypeName { get; set; }
}
public class ClassTypes
{
public List<Type> Types { get; set; }
}
public class MyClass
{
public int Id { get; set; }
public Names Names { get; set; }
public ClassTypes ClassTypes { get; set; }
public string Status { get; set; }
public string DOB { get; set; }
}
...
var result = JsonConvert.DeserializeObject<MyClass>(jsonString);
Classes created by http://json2csharp.com/
Upvotes: 2