Reputation: 33
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.
Upvotes: 1
Views: 1125
Reputation: 1
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"?
Upvotes: 0
Reputation: 218798
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.
Upvotes: 1
Reputation:
Try paymentTermsDays property to int? because null value not set int property.
Upvotes: 0