1

I am calling an API but I have some trouble deserializing it afterwards.

Here's what I am trying to do:

            var result = response.Content.ReadAsStringAsync().Result;
            dynamic data = JObject.Parse(result);
            var contacts = JsonConvert.DeserializeObject<List<Contact>>(data.contacts);
            return contacts;

but the deserializing gives an error:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The best overloaded method match for 
'Newtonsoft.Json.JsonConvert.DeserializeObject<System.Collections.Generic.List<Moneti.API.Models.Contact>>(string)' has some invalid 
arguments    at CallSite.Target(Closure , CallSite , Type , Object )

Here is what gets parsed to the dynamic data:

{
  "meta": {
    "statusCode": 200,
    "success": true,
    "paging": {
       "page": 1,
       "pageSize": 1000,
        "pageCount": 1,
        "total": 11
   },
"time": 0.030631065368652
},
"contacts": [
{
  "id": "Id",
  "type": "person",
  "organizationId": "OrgId",
  "createdTime": "2020-07-08T12:04:59",
  "name": "From ContactController",
  "countryId": "DE",
  "street": "",
  "cityId": null,
  "cityText": "",
  "stateId": null,
  "stateText": "",
  "zipcodeId": null,
  "zipcodeText": "",
  "contactNo": "",
  "phone": "",
  "fax": "",
  "currencyId": null,
  "registrationNo": "",
  "ean": "",
  "localeId": null,
  "isCustomer": true,
  "isSupplier": false,
  "paymentTermsMode": null,
  "paymentTermsDays": null,
  "accessCode": "",
  "emailAttachmentDeliveryMode": null,
  "isArchived": false,
  "isSalesTaxExempt": false,
  "defaultExpenseProductDescription": null,
  "defaultExpenseAccountId": null,
  "defaultTaxRateId": null
},
{
  "id": "Id",
  "type": "person",
  "organizationId": "OrgId",
  "createdTime": "2020-07-08T10:21:31",
  "name": "From ContactController",
  "countryId": "DE",
  "street": "",
  "cityId": null,
  "cityText": "",
  "stateId": null,
  "stateText": "",
  "zipcodeId": null,
  "zipcodeText": "",
  "contactNo": "",
  "phone": "",
  "fax": "",
  "currencyId": null,
  "registrationNo": "",
  "ean": "",
  "localeId": null,
  "isCustomer": true,
  "isSupplier": false,
  "paymentTermsMode": null,
  "paymentTermsDays": null,
  "accessCode": "",
  "emailAttachmentDeliveryMode": null,
  "isArchived": false,
  "isSalesTaxExempt": false,
  "defaultExpenseProductDescription": null,
  "defaultExpenseAccountId": null,
  "defaultTaxRateId": null
},

and here's the Contact class I'm trying to deserialize it to. I have used json2csharp for converting it:

public class Contact
{
    public string id { get; set; }
    public string type { get; set; }
    public string organizationId { get; set; }
    public DateTime createdTime { get; set; }
    public string name { get; set; }
    public string countryId { get; set; }
    public string street { get; set; }
    public string cityId { get; set; }
    public string cityText { get; set; }
    public string stateId { get; set; }
    public string stateText { get; set; }
    public string zipcodeId { get; set; }
    public string zipcodeText { get; set; }
    public string contactNo { get; set; }
    public string phone { get; set; }
    public string fax { get; set; }
    public string currencyId { get; set; }
    public string registrationNo { get; set; }
    public string ean { get; set; }
    public string localeId { get; set; }
    public bool isCustomer { get; set; }
    public bool isSupplier { get; set; }
    public int paymentTermsDays { get; set; }
    public string accessCode { get; set; }
    public string emailAttachmentDeliveryMode { get; set; }
    public bool isArchived { get; set; }
    public bool isSalesTaxExempt { get; set; }
    public string defaultExpenseProductDescription { get; set; }
    public string defaultExpenseAccountId { get; set; }
    public string defaultTaxRateId { get; set; }
}

but it doesn't allow me to deserialize it. I do not have access to the API besides calling it.

1
  • That is not valid json, I assume it is not the complete response you actually get? Commented Jul 8, 2020 at 13:21

3 Answers 3

1

It sounds like data.contacts isn't a string. When the original string was parsed into data it became a dynamic, which is representing the object itself and not the JSON string.

I'd skip the dynamic part entirely and just deserialize the entire JSON. You don't need every property, if all you want are the contacts then just include that one property on the containing class:

public class Container
{
    public IList<Contact> contacts { get; set; }
}

Then deserialize the originating JSON into that containing class:

var result = response.Content.ReadAsStringAsync().Result;
var container = JsonConvert.DeserializeObject<Container>(result);
return container.contacts;

Side note: Reading .Result directly is almost always a bad idea. Instead, consider making your method async (returning a Task<IList<Contact>>) and using await to get the result:

var result = await response.Content.ReadAsStringAsync();
var container = JsonConvert.DeserializeObject<Container>(result);
return container.contacts;

Other observations: This also doesn't look like it'll work:

public int paymentTermsDays { get; set; }

Because the data is null:

"paymentTermsDays": null,

An int can not be null. The deserialization might silently set this to 0, or might throw an error, but both of those scenarios are not ideal. The model needs to correctly match the expected data. Instead of int, use Nullable<int>:

public int? paymentTermsDays { get; set; }

This may require some minor changes elsewhere in your code to account for this property being a different type.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot, this works. I wanted to do it async but every time I tried the server returned some weird ass response and as soon as I changed it I got my data so I just assumed the API didn't allow to access it async
@eeee: Most likely this should be async and there was an error in your attempt. What you have now may work coincidentally, but can easily lead to very difficult to diagnose bugs the moment it stops working.
Thanks, I will look at it tomorrow if I could fix it - otherwise contact them.
0

Try paymentTermsDays property to int? because null value not set int property.

1 Comment

I've tried changing it to a string already, it didn't solve anything. I cannot just expect it to be set
0

My solution is without creating a class:

        dynamic data = JObject.Parse(result);
        if (data.GetValue("contacts") is JArray contacts) {
            return contacts.Select(x => JsonConvert.DeserializeObject<Contact>(x.ToString())).ToList();
        }

PS: You should to pay attention to your model. You have already known about "paymentTermsDays". And what about "paymentTermsMode"?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.