Reputation: 5619
The business rules are simple. We have a method that takes a JObject as a parm. Convert it to a c# poco.
The json needs to represent a single object.
No arrays allowed. If you need to do it three times call the method three times.
So for example this would be valid json:
{
"CustomerId": 669616948,
"FirstName": "ERIC",
"LastName": "TEST2",
"BirthYear": 0,
"BirthMonth": 0,
"CustomerState": 0,
"LegalAddressState": null,
"Username": "ERIC2222"
}
this would not:
{
"Participants": [
{
"CustomerId": 669616948,
"FirstName": "ERIC",
"LastName": "TEST2",
"BirthYear": 0,
"BirthMonth": 0,
"CustomerState": 0,
"LegalAddressState": null,
"Username": "ERIC2222"
}
]
}
Currently this throws an exception when it tries to convert to a poco and while we can handle the exception I was looking for a way to detect if the JObject contained an array and gracefully exit.
So the json above is just a representation of what the JObject would look like but it IS a JObject.
The best I have been able to come up with is a measly string check.
JObject.ToString().Contains("[")
Any ideas on how to do an array check. If I could somehow get it to a JToken then I could do this (temp is of type JToken):
temp.Type == JTokenType.Array
TIA
As requested here is the conversion. payload is a JObject.
var customer = payload.ToObject<Customer>(_serializer);
Upvotes: 1
Views: 5950
Reputation: 1985
Am not quite sure about your requirements. But this is one way to go:
[TestMethod]
public void DeserializeTest()
{
var jsonStr1 = "{\"CustomerId\": 669616948,\"FirstName\": \"ERIC\",\"LastName\": \"TEST2\",\"BirthYear\": 0,\"BirthMonth\": 0,\"CustomerState\": 0,\"LegalAddressState\": null,\"Username\": \"ERIC2222\"}";
JToken token1 = JToken.Parse(jsonStr1);
var participantsFromToken1 = token1["Participants"];
Console.WriteLine(participantsFromToken1 != null && participantsFromToken1.Type == JTokenType.Array
? "Hey, token1 is an array"
: "Hey, token1 is not an array");
var jsonStr2 =
"{\"Participants\": [{\"CustomerId\": 669616948,\"FirstName\": \"ERIC\",\"LastName\": \"TEST2\",\"BirthYear\": 0,\"BirthMonth\": 0,\"CustomerState\": 0,\"LegalAddressState\": null,\"Username\": \"ERIC2222\"}]}";
JToken token2 = JToken.Parse(jsonStr2);
var participantsFromToken2 = token2["Participants"];
Console.WriteLine(participantsFromToken2 != null && participantsFromToken2.Type == JTokenType.Array
? "Hey, token2 is an array"
: "Hey, token2 is not an array");
}
Upvotes: 0
Reputation: 33833
You can always write a custom JsonConverter
that walks the json tree (using a technique such as that described in this answer https://stackoverflow.com/a/19646950/1165998), checking both the type and the value type for JArray
and returning null if it is:
public class ProhibitArraysConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var jsonObject = JToken.Load(reader);
if (ContainsArray(jsonObject))
return null;
T target = (T)Activator.CreateInstance(objectType);
serializer.Populate(jsonObject.CreateReader(), target);
return target;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(T);
}
private static bool ContainsArray(JToken containerToken)
{
if (containerToken.Type == JTokenType.Object)
{
foreach (JProperty child in containerToken.Children<JProperty>())
{
if (child.Type == JTokenType.Array ||
child.Value.Type == JTokenType.Array)
{
return true;
}
ContainsArray(child.Value);
}
}
else if (containerToken.Type == JTokenType.Array)
{
return true;
}
return false;
}
}
This will return the deserialized data in your first example and null for your second.
Upvotes: 1
Reputation: 7846
What about this way?
dynamic value = jToken["Participants"];
if (value != null && value is JArray)
{
//gracefully exit.
}
Upvotes: 2