0

I have spent all day referencing numerous posts and trying all sorts of different techniques for resolving this issue, to no avail. My failures may just be the result of a lack of understanding, but I have never experienced this kind of problem before so I have arrived at something of an impasse.

Given the following JSON as a string received from a WebService request ...

{
    "contacts": [{
        "identities": [{
            "vid": 40451,
            "identity": [{
                "value": "bsmith@aol.com",
                "type": "EMAIL",
                "timestamp": 4556668881236,
                "isPrimary": true
            },
            {
                "value": "a2c53333-3333-3333-3333-34bc21723333",
                "type": "LEAD_GUID",
                "timestamp": 4556668881236
            }],
            "linkedVid": []
        }],
        "properties": [{
            "name": "firstname",
            "value": "Bob",
            "sourceVid": []
        },
        {
            "name": "lastmodifieddate",
            "value": "151512112212",
            "sourceVid": []
        },
        {
            "name": "lastname",
            "value": "Smith",
            "sourceVid": []
        }],
        "formSubmissions": [],
        "listMembership": [],
        "vid": 44444,
        "portalId": 4444444,
        "isContact": true,
        "vids": [],
        "imports": [],
        "publicToken": "kshdfkjhsdsdjfjkdhshjksd",
        "canonicalVid": 44444,
        "mergeAudit": [],
        "mergedVids": [],
        "campaigns": [],
        "stateChanges": []
    }, {
        ... 
    }, {
        ... 
    }]
}

When I try to deserialize the list of contacts ...

String jsonString = obj.GetJson();
var response = Newtonsoft.Json.JsonConvert.DeserializeObject<HSContactListResult>(
    jsonString,
    new Newtonsoft.Json.JsonSerializerSettings
    {
        TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All,
        NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
    });

I get the error message ...

Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'HSContactIdentityProfile' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'contacts[0].identities', line 1, position 28

The following classes represent the which the JSON is deserialized into ...

[Serializable]
[DataContract]
public class HSContactListResult 
{
    [DataMember(Name ="hasMore")]
    public bool HasMore { get; set; }

    [DataMember(Name = "vidOffset")]
    public long Offset { get; set; }


    [DataMember(Name = "contacts")]
    public List<Companies.Models.HSContact> Contacts{ get; set; }


    public Int32 Count { get { return this.Contacts.Count; } }


    public HSContactListResult()
    {
        this.Contacts = new List<Companies.Models.HSContact>().ToList();
    }

}


[Serializable]
[DataContract]
public class HSContact
{
    [DataMember(Name = "vid")]
    public long ContactId { get; set;  }

    [DataMember(Name = "portalId")]
    public long PortalId { get; set; }

    [DataMember(Name = "isContact")]
    public bool IsContact { get; set; }

    [DataMember(Name = "properties")]
    public Companies.Models.HSContactProperties Properties { get; set; }

    [DataMember(Name = "identities")]
    public Companies.Models.HSContactIdentityProfile IdentityProfiles { get; }

    public HSCompany Company { get; set; }

    #region c-tor
    public HSContact()
    {
        this.Properties = new Companies.Models.HSContactProperties();
        this.IdentityProfiles = new Companies.Models.HSContactIdentityProfile();
    }
    #endregion c-tor
}


[Serializable]
[DataContract]
public class HSContactProperties: IHSContactProperties
{
    [DataMember(Name ="firstname")]
    public HSProperty FirstName { get; set; }

    [DataMember(Name = "lastname")]
    public HSProperty LastName { get; set; }

    [DataMember(Name = "company")]
    public HSProperty CompanyName { get; set; }
}


[Serializable]
[DataContract]
public class HSContactIdentityProfile 
{
    [DataMember(Name = "vid")]
    public Int64 ContactID { get; set; }


    [DataMember(Name = "identity")]
    public List<Companies.Models.HSContactIdentity> Identities { get; set; }


    [DataMember(Name = "saved-at-timestamp")]
    public Int64 saved_at_timestamp { get; set; }

    [DataMember(Name = "deleted-changed-timestamp")]
    public Int64 deleted_changed_timestamp { get; set; }


    public HSContactIdentityProfile()
    {
        this.Identities = new List<Companies.Models.HSContactIdentity>().ToList();
    }
}


[Serializable]
[DataContract]
public class HSContactIdentity : IHSContactIdentity
{

    [DataMember(Name = "type")]
    public string Type { get; set; }

    [DataMember(Name = "value")]
    public string Value { get; set; }

    [DataMember(Name = "timestamp")]
    public long Timestamp { get; set; }

    [DataMember(Name = "isPrimary")]
    public bool IsPrimary { get; set; }
}

The problem appears to be that Newtonsoft wants to deserialize the HSContactIdentityProfile instance into an Array even though it's actually an object. The property "Identities" IS an array and since it seems to be cvalled out I am assuming that that is interfering with the desrialization process. I don't understand however why it's just not deserializing the List as a property of the HSContactIdentityProfile object.

I have tried custom converters but may have done those incorrectly (first time with this). I am not sure what else to try. After trying to implement 5 or 6 of the "fixes" presented in other potential duplicate posts I have not been able to resolve it.

E_net4
  • 27,810
  • 13
  • 101
  • 139
Gary O. Stenstrom
  • 2,284
  • 9
  • 38
  • 59
  • 1
    test your model with http://json2csharp.com/ – L.B Nov 30 '18 at 22:03
  • 1
    Or copy the json to the clipboard and use _Edit_ -> _Paste Special_ -> _Paste JSON As Classes_ in Visual Studio ;-) – Markus Safar Nov 30 '18 at 22:19
  • 1
    In your JSON, `"identities"` is an array, not an object. But if it is sometimes an array, and sometimes a single object, see [How to handle both a single item and an array for the same property using JSON.net](https://stackoverflow.com/q/18994685/3744182). – dbc Nov 30 '18 at 22:52
  • 1
    @MarkusSafar I never knew that was possible!! Awesome! Thanks! – Gary O. Stenstrom Dec 03 '18 at 15:26
  • 2
    @L.B Fantastic. I did not realize that these tools were available. You and MarkusSafar have just made my life much easier! Thanks again. – Gary O. Stenstrom Dec 03 '18 at 15:28

1 Answers1

0

As per the error message:

[DataMember(Name = "identities")]
public Companies.Models.HSContactIdentityProfile IdentityProfiles { get; }

should be a list or array:

[DataMember(Name = "identities")]
public List<Companies.Models.HSContactIdentityProfile> IdentityProfiles { get; }

Your original code would work if the original JSON was:

"contacts": { "identities"

but alas it is "contacts": [{ "identities"

(the extra [ meaning a JSON array is involved)

mjwills
  • 23,389
  • 6
  • 40
  • 63