1

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);
Jim Hewitt
  • 1,726
  • 4
  • 24
  • 26
GPGVM
  • 5,515
  • 10
  • 56
  • 97
  • Your both samples are valid json... See http://jsonlint.com/# – L.B Oct 18 '16 at 21:03
  • Maybe create a schema and validate it [with Newtonsoft](http://www.newtonsoft.com/json/help/html/JsonSchema.htm) or like tool. – Crowcoder Oct 18 '16 at 21:05
  • @GiladGreen code posted for the poco conversion – GPGVM Oct 18 '16 at 21:11
  • @GiladGreen So you wouldn't mind if I vote to close it as "unclear what is asked.." – L.B Oct 18 '16 at 21:11
  • @GPGVM - see this: [Searching for a specific JToken by name in a JObject hierarchy](http://stackoverflow.com/q/19645501/6400526). Change from searching my name to check type – Gilad Green Oct 18 '16 at 21:44
  • It looks like that you want to check the content of json, so json schema is the right choice. – zhimin Oct 18 '16 at 22:00

3 Answers3

1

What about this way?

dynamic value = jToken["Participants"];
if (value != null && value is JArray)
{
 //gracefully exit.
}
Ilya Sulimanov
  • 7,636
  • 6
  • 47
  • 68
1

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.

Community
  • 1
  • 1
David L
  • 32,885
  • 8
  • 62
  • 93
0

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");
        }
sam
  • 1,937
  • 1
  • 8
  • 14