none
Nulls after deserialising from JSON RRS feed

  • Question

  • Hi there,

    Looking for some assistance. I've getting data from the SalesForce API and some records will have data in its Parent, some wont have data in their Parent record because they dont have parents or the data isnt there.

    I'm managing to deserialise the data from the returned JSON using 

    RootObject returnedData = JsonConvert.DeserializeObject<RootObject>(data);
    
                foreach(var rootObject in returnedData.records)
                {
                    record = rootObject;
                }                   
                

    The classes are:

        public class RootObject
        {
            public int totalSize { get; set; }
            public bool done { get; set; }
            public Record[] records { get; set; }
        }
    
     public class Record
        {
            public Attributes attributes { get; set; }
            
            public string Name { get; set; }
            [JsonProperty("Account_Number__c")]
            public string  Abta { get; set; }
    
            public Parent parent { get; set; }
            public Owner owner { get; set; }
        }
    
        public class Attributes
        {
            public string type { get; set; }
            public string url { get; set; }
        }
    
     public class Parent
        {
            public Attributes attributes { get; set; }
            [JsonProperty("Account_Number__c")]
            public string Abta { get; set; }
            public string Name { get; set; }
        }
    
        public class Owner
        {
            public Attributes attributes { get; set; }
    
            [JsonProperty("KamName")]
            public string Name { get; set; }
        }

    I'm then doing the following:

    Record returnedRecord = GetRecordData(bearerToken, item);
                    
                    string AgentName = returnedRecord.Name == null ? "UnknownAgentName" : returnedRecord.Name;
                    string AgentAbta = returnedRecord.Abta == null ? "UnknownAgentAbta" : returnedRecord.Abta;
                    string ParentName = returnedRecord.parent.Name == null ? "UnknownParentName" : returnedRecord.parent.Name;
                    string ParentAbta = returnedRecord.parent.Abta == null ? "UnknownParentAbta" : returnedRecord.parent.Abta;
                    string KamName = returnedRecord.owner == null ? "UnknownKAM" : returnedRecord.owner.Name;
    
                    Console.WriteLine("{0} {1} {2} {3} {4}", AgentName, AgentAbta, ParentName, ParentAbta, KamName);

    In some cases AgentAbta will be null and I "UnknownAgetAbta" - works fantastic.

    In the current state if ParentAbta is NULL, I get a NULL reference. If I remove .Name, it always equates to NULL and I always get UnknownParentAbta.

    I think I maybe missing something quite obvious here and google isnt helping!

    It C# 7.3.

    Thanks for any assistance you can offer!


    Tuesday, December 31, 2019 1:39 PM

Answers

  • Here's the big gap in what you're postin - `GetRecordData`. You haven't posted the impl of that method and it looks like it is the API call. Is that where you're calling `JsonConvert` or are you calling it on something else. The code you're posting for calling it doesn't line up with the fact that your method supposedly returns a single `Record`. 

    Here's a version that I put together that mostly fits into your original code.

    static void Main(string[] args)
    {
        var bearerToken = "";
        var item = 1;
        var returnedRecords = GetRecordData(bearerToken, item);
    
        foreach (var returnedRecord in returnedRecords)
        {
            string AgentName = returnedRecord.Name == null ? "UnknownAgentName" : returnedRecord.Name;
            string AgentAbta = returnedRecord.Abta == null ? "UnknownAgentAbta" : returnedRecord.Abta;
            string ParentName = returnedRecord.parent.Name == null ? "UnknownParentName" : returnedRecord.parent.Name;
            string ParentAbta = returnedRecord.parent.Abta == null ? "UnknownParentAbta" : returnedRecord.parent.Abta;
            string KamName = returnedRecord.owner == null ? "UnknownKAM" : returnedRecord.owner.Name;
    
            Console.WriteLine("{0} {1} {2} {3} {4}", AgentName, AgentAbta, ParentName, ParentAbta, KamName);
        };
    }        
    
    static IEnumerable<Record> GetRecordData ( string bearerToken, int item )
    {
        //Load the sample JSON from a file
        var data = System.IO.File.ReadAllText("test.json");
    
        RootObject returnedData = JsonConvert.DeserializeObject<RootObject>(data);
    
        return returnedData.records;
        //foreach (var rootObject in returnedData.records)
        //{
        //    record = rootObject;
        //}       
    }

    The JSON you posted I put into a test file and load it. That would be different from your calling an API but the results would be the same. After that the given JSON blows up when referencing the name as you originally described. So we can fix that part as I mentioned earlier.

    foreach (var returnedRecord in returnedRecords)
        {
            string AgentName = returnedRecord.Name ?? "UnknownAgentName";
            string AgentAbta = returnedRecord.Abta ?? "UnknownAgentAbta";
            string ParentName = returnedRecord.parent?.Name ?? "UnknownParentName";
            string ParentAbta = returnedRecord.parent?.Abta ?? "UnknownParentAbta";
            string KamName = returnedRecord.owner?.Name ?? "UnknownKAM";
    
            Console.WriteLine("{0} {1} {2} {3} {4}", AgentName, AgentAbta, ParentName, ParentAbta, KamName);
        };

    Now the code executes properly without errors.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by dwjenkins Wednesday, January 8, 2020 11:15 AM
    Tuesday, January 7, 2020 4:50 PM
    Moderator

All replies

  • I would look at the json you are deserializing.  Maybe something has changed so the parent is not getting deserialized properly.
    Tuesday, December 31, 2019 1:49 PM
  • Thank you for taking the time to respond, especially on New Years eve.

    I ran a good record through and it does deserialise properly to the classes as I'd expect it to.

    I then tested on a record that I know is missing data, the parent object in the JSON is NULL. Whats the best way to handle it? I thought that the following would of handled it (but I'm still relatively newbie to this!

    record.parent.Name = rootObject.parent.Name == null ? "UnknownParentName" : rootObject.parent.Name;

    Tuesday, December 31, 2019 2:09 PM
  • If you want to handle a potentially null reference object then you can use the null conditional (?.) or null coalescing (??) operators, depending upon your needs.

    Null coalescing works just like a database coalesce. It takes a series of expressions and returns the first non-null.

    var actualName = name ?? "";

    It is semantically equivalent to this lengthy code but optimized.

    var actualName = name
    if (name == null)
       actualName = "";

    Null conditional is used to call a member on an object only if the object isn't null. If the object is null then it skips the call and returns null instead. 

    var results = person?.GetResults();

    It is semantically equivalent to this.

    var results = null;
    if (person != null)
       results = person.GetResults();

    We often combine them together.

    //Set to either the person's name if person and name is not null or empty string otherwise
    var actualName = person?.Name ?? "";

    So to handle your specific case you can do this.

    record.parent.Name = rootObject.parent?.Name ?? "UnknownParentName";

    However given that you are referencing several `parent` properties you might do better to simply use an `if` statement around this block to limit it to one check.

    Also note that generally we treat empty strings and null strings the same so in general use `String.IsNullOrEmpty` instead of comparing a string against `null` directly.

    record.parent.Name = String.IsNullOrEmpty(rootObject.parent?.Name) ? "UnknownParentName" : rootObject.parent.Name;


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, December 31, 2019 7:21 PM
    Moderator
  • Hi dwjenkins, 

    Thank you for posting here.

    According to your description, I need more information to make a test.

    >> In the current state if ParentAbta is NULL, I get a NULL reference. If I remove .Name, it always equates to NULL and I always get UnknownParentAbta.

    Could you provide your related json string here? It will help us to analyze your problem and make a test.

    Besides, we can supply settings to JsonConvert.DeserializeObject to tell it how to handle null values.

                var settings = new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore,
                    MissingMemberHandling = MissingMemberHandling.Ignore
                };
               
                var jsonModel = JsonConvert.DeserializeObject<RootObject>(jsonString);
    

    Here’s a reference you can refer to.

    How to ignore a property in class if null, using json.net

    Hope it can help you.

    Best Regards,

    Xingyu Zhao



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, January 1, 2020 7:02 AM
    Moderator
  • Hi dwjenkins,

    Did you solve your problem? If your question has been answered then please click the "Mark as Answer" Link at the bottom of the correct post(s), so that it will help other members to find the solution quickly if they face a similar issue.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Tuesday, January 7, 2020 6:45 AM
    Moderator
  • Apologies for the delay.

    Here's a sample of the JSON.

    { 
    "totalSize":1,
    "done":true,
    "records":[ 
    { 
    "attributes":{ 
    "type":"Account",
    "url":"/services/data/v47.0/sobjects/Account/0010N000XXXfU8QAI"
    },
    "Name":"Random Name",
    "Account_Number__c":"262a4c",
    "Parent":null,
    "Owner":{ 
    "attributes":{ 
    "type":"User",
    "url":"/services/data/v47.0/sobjects/User/0050NXXX08Z02kQAC"
    },
    "Name":"James Bond"
    }
    }
    ]
    }


    I've tried adding the following as per the example:

       RootObject returnedData = JsonConvert.DeserializeObject<RootObject>(data, new JsonSerializerSettings            {                NullValueHandling = NullValueHandling.Ignore            });

    I also tried CoolDads awesome explanation, but I could get them working.

    Thank you for all the responses so far.

    Tuesday, January 7, 2020 11:00 AM
  • Here's the big gap in what you're postin - `GetRecordData`. You haven't posted the impl of that method and it looks like it is the API call. Is that where you're calling `JsonConvert` or are you calling it on something else. The code you're posting for calling it doesn't line up with the fact that your method supposedly returns a single `Record`. 

    Here's a version that I put together that mostly fits into your original code.

    static void Main(string[] args)
    {
        var bearerToken = "";
        var item = 1;
        var returnedRecords = GetRecordData(bearerToken, item);
    
        foreach (var returnedRecord in returnedRecords)
        {
            string AgentName = returnedRecord.Name == null ? "UnknownAgentName" : returnedRecord.Name;
            string AgentAbta = returnedRecord.Abta == null ? "UnknownAgentAbta" : returnedRecord.Abta;
            string ParentName = returnedRecord.parent.Name == null ? "UnknownParentName" : returnedRecord.parent.Name;
            string ParentAbta = returnedRecord.parent.Abta == null ? "UnknownParentAbta" : returnedRecord.parent.Abta;
            string KamName = returnedRecord.owner == null ? "UnknownKAM" : returnedRecord.owner.Name;
    
            Console.WriteLine("{0} {1} {2} {3} {4}", AgentName, AgentAbta, ParentName, ParentAbta, KamName);
        };
    }        
    
    static IEnumerable<Record> GetRecordData ( string bearerToken, int item )
    {
        //Load the sample JSON from a file
        var data = System.IO.File.ReadAllText("test.json");
    
        RootObject returnedData = JsonConvert.DeserializeObject<RootObject>(data);
    
        return returnedData.records;
        //foreach (var rootObject in returnedData.records)
        //{
        //    record = rootObject;
        //}       
    }

    The JSON you posted I put into a test file and load it. That would be different from your calling an API but the results would be the same. After that the given JSON blows up when referencing the name as you originally described. So we can fix that part as I mentioned earlier.

    foreach (var returnedRecord in returnedRecords)
        {
            string AgentName = returnedRecord.Name ?? "UnknownAgentName";
            string AgentAbta = returnedRecord.Abta ?? "UnknownAgentAbta";
            string ParentName = returnedRecord.parent?.Name ?? "UnknownParentName";
            string ParentAbta = returnedRecord.parent?.Abta ?? "UnknownParentAbta";
            string KamName = returnedRecord.owner?.Name ?? "UnknownKAM";
    
            Console.WriteLine("{0} {1} {2} {3} {4}", AgentName, AgentAbta, ParentName, ParentAbta, KamName);
        };

    Now the code executes properly without errors.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by dwjenkins Wednesday, January 8, 2020 11:15 AM
    Tuesday, January 7, 2020 4:50 PM
    Moderator
  • Hi Micheal/CoolDad :D

    Thank you, as you pointed out, the key was that it was returning one record at a time.

    Legend!

    Dave.

    Wednesday, January 8, 2020 11:14 AM