Cannot access child value on Newtonsoft.Json.Linq.JValue error? - c#

string shippingContactFullName = (string)json["billing_address"]["contact_full_name"];
On this line, i get the
Cannot access child value on Newtonsoft.Json.Linq.JValue error
The ShippingAddress element is working. But I'm getting the error you see in the BillingAdress element.
How can I solve this problem?
JSON:
{
"id": 53245235,
"service": 2,
"service_name": "n11",
"service_logo": "https://dopigo.s3.amazonaws.com/integration_logos/n11_2.png",
"sales_channel": "n11",
"service_created": "2022-01-20T00:59:00+03:00",
"service_value": "207843149357",
"service_order_id": "298190201",
"products": "3 X (216109) Akü Kutup Başı - Zamak Malzeme<br>3 X (216109) Akü Kutup Başı - Zamak Malzeme<br>",
"customer": {
"id": 26207836,
"account_type": "person",
"full_name": "tuncay poyraz",
"address": {
"id": 81237558,
"full_address": "Foça Mh. Foca mah 1041 sok kapi daire 11/6 s blok fethiye - FETHİYE/Muğla/TürkiyeFOÇA /FETHİYE /MuğlaT",
"contact_full_name": null,
"contact_phone_number": null,
"city": "Muğla",
"district": "Fethiye",
"zip_code": null
},
"email": "tayfun6023#gmail.com",
"phone_number": "+905536925506",
"citizen_id": 38576088320,
"tax_id": null,
"tax_office": null,
"company_name": null,
"service_data_mappings": [
{
"service_data": {
"service": {
"name": "n11"
},
"service_value": "17878401"
}
}
]
},
"billing_address": {
"id": 81237553,
"full_address": "Foça Mh. Foca mah 1041 sok kapi daire 11/6 s blok fethiye - FETHİYE/Muğla/TürkiyeFOÇA /FETHİYE /MuğlaT",
"contact_full_name": "bekir dirican",
"contact_phone_number": "+905536925506",
"city": "Muğla",
"district": "Fethiye",
"zip_code": "48300"
},
"shipping_address": {
"id": 81237554,
"full_address": "Foça Mh. Foca mah 1041 sok kapi daire 11/6 s blok fethiye - FETHİYE/Muğla/TürkiyeFOÇA /FETHİYE /MuğlaT",
"contact_full_name": "bekir dirican",
"contact_phone_number": "+905536925506",
"city": "Muğla",
"district": "Fethiye",
"zip_code": "48300"
},
"shipped_date": null,
"payment_type": "cc",
"status": "waiting_shipment",
"total": "54.00",
"service_fee": null,
"discount": null,
"archived": false,
"notes": null,
"items": [
{
"id": 35478059,
"order": 53245235,
"service_item_id": "319332749",
"service_product_id": "524383019",
"service_shipment_code": null,
"sku": "216109",
"attributes": "Kutup Yön Seçin: Eksi Kutup (-), ",
"name": "Akü Kutup Başı - Zamak Malzeme",
"amount": 3,
"price": "27.00",
"unit_price": "9.00",
"shipment": null,
"shipment_campaign_code": "112064897331519",
"buyer_pays_shipment": false,
"status": "approved",
"shipment_provider": 3,
"tax_ratio": 18,
"product": {
"id": 17022813,
"sku": "AK-KTP-BS-MLZM-2",
"foreign_sku": "216109E"
},
"linked_product": {
"id": 17022813,
"sku": "AK-KTP-BS-MLZM-2",
"foreign_sku": "216109E"
},
"vat": null
},
{
"id": 35478058,
"order": 53245235,
"service_item_id": "319348650",
"service_product_id": "524383019",
"service_shipment_code": null,
"sku": "216109",
"attributes": "Kutup Yön Seçin: Artı Kutup (+), ",
"name": "Akü Kutup Başı - Zamak Malzeme",
"amount": 3,
"price": "27.00",
"unit_price": "9.00",
"shipment": null,
"shipment_campaign_code": "112064897331519",
"buyer_pays_shipment": false,
"status": "approved",
"shipment_provider": 3,
"tax_ratio": 18,
"product": {
"id": 17022810,
"sku": "AK-KTP-BS-MLZM",
"foreign_sku": "216109A"
},
"linked_product": {
"id": 17022810,
"sku": "AK-KTP-BS-MLZM",
"foreign_sku": "216109A"
},
"vat": null
}
],
"transactions": [
{
"transaction_type": "income",
"payment_type": "undefined",
"additional_description": "Gelir",
"paid_date": "2022-01-20T00:59:00+03:00",
"payment_due_date": null,
"invoice_number": null,
"invoice_file": null,
"service_document_url": null,
"total": "54.00",
"archived": false,
"installment_count": null,
"pos_ref_id": null,
"bank_id": null,
"account_id": null
},
{
"transaction_type": "expense",
"payment_type": "undefined",
"additional_description": "komisyon",
"paid_date": "2022-01-20T00:59:00+03:00",
"payment_due_date": null,
"invoice_number": null,
"invoice_file": null,
"service_document_url": null,
"total": "5.40",
"archived": false,
"installment_count": null,
"pos_ref_id": null,
"bank_id": null,
"account_id": null
}
],
"invoice_number": "PA02022000000294",
"invoice_created": "2022-01-20T06:23:05.608248Z",
"invoice_type": "e-archive",
"invoice_vat_total": 8.24,
"invoice_grand_total": 54.0,
"invoice_deleted": false,
"created": "2022-01-20T01:09:21.717504+03:00"
}

Related

Restsharp JSON response search

I need to search the following JSON response. I have no control over how the JSON is returned to me or how it is nested. I am using Restsharp by default, but I am open to whatever method helps me accomplish the task.
{
"response": [
{
"id": 1008,
"brandId": 74,
"collectionId": 32,
"productTypeId": 1,
"nominalCodeStock": "1200",
"nominalCodePurchases": "5002",
"nominalCodeSales": "4000",
"seasonIds": [
],
"identity": {
"sku": "SKU0001",
"isbn": "0684843285",
"ean": "ISNB09712345",
"upc": "5778400001",
"barcode": "738737638"
},
"productGroupId": 0,
"featured": false,
"stock": {
"stockTracked": true,
"weight": {
"magnitude": 0.7
},
"dimensions": {
"length": 2,
"height": 12,
"width": 5,
"volume": 120
}
},
"financialDetails": {
"taxCode": {
"id": 7,
"code": "T20"
}
},
"salesChannels": [
{
"salesChannelName": "Brightpearl",
"productName": "Product B",
"productCondition": "new",
"categories": [
{
"categoryCode": "276"
},
{
"categoryCode": "295"
}
],
"description": {
"languageCode": "en",
"text": "Some description",
"format": "HTML_FRAGMENT"
},
"shortDescription": {
"languageCode": "en",
"text": "Some short description",
"format": "HTML_FRAGMENT"
}
}
],
"composition": {
"bundle": false
},
"variations": [
{
"optionId": 1,
"optionName": "Colour",
"optionValueId": 1,
"optionValue": "Black"
},
{
"optionId": 3,
"optionName": "Colour",
"optionValueId": 9,
"optionValue": "Black"
}
],
"warehouses": {
"2": {
"defaultLocationId": 5,
"reorderLevel": 1,
"reorderQuantity": 0
},
"3": {
"defaultLocationId": 0,
"reorderLevel": 1,
"reorderQuantity": 1
}
},
"createdOn": "2015-01-08T17:57:18.000Z",
"updatedOn": "2015-04-01T13:17:58.000Z",
"reporting": {
"categoryId": 353,
"subcategoryId": 369,
"seasonId": 2
},
"primarySupplierId": 202,
"status": "LIVE",
"salesPopupMessage": "Offer the extended warranty",
"version": 1192098806000
}
]
}
Specifically I need to retrieve the categoryCode values. I'm lost on this one. Any direction is much appreciated.

Json.net deserialize array of varible types in c#

I have a third-party API that is returning a JSON object with an array with varying types.
For example, one array json object looks something like this:
[{
"text": "<p>Introduction</p>",
"id": 13273,
"item_type": "Message",
"page_id": 5292,
"position": 1,
"alias": null,
"html_class": null,
"include_condition": null
}, {
"text": "<p><span style=\"background-color: transparent; color: rgb(0, 0, 0);\">Value Proposition</span></p>",
"id": 13274,
"item_type": "Message",
"page_id": 5292,
"position": 2,
"alias": null,
"html_class": null,
"include_condition": null
}, {
"start_value": 0,
"end_value": 10,
"start_text": "Not At All Common Need",
"mid_text": null,
"end_text": "Extremely Common Need",
"enable_not_applicable": false,
"not_applicable_text": null,
"choices": [{
"id": 43181,
"text": "0",
"alias": null,
"position": 1,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 0.0000,
"image": null
}, {
"id": 43182,
"text": "1",
"alias": null,
"position": 2,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 1.0000,
"image": null
}, {
"id": 43183,
"text": "2",
"alias": null,
"position": 3,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 2.0000,
"image": null
}, {
"id": 43184,
"text": "3",
"alias": null,
"position": 4,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 3.0000,
"image": null
}, {
"id": 43185,
"text": "4",
"alias": null,
"position": 5,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 4.0000,
"image": null
}, {
"id": 43186,
"text": "5",
"alias": null,
"position": 6,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 5.0000,
"image": null
}, {
"id": 43187,
"text": "6",
"alias": null,
"position": 7,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 6.0000,
"image": null
}, {
"id": 43188,
"text": "7",
"alias": null,
"position": 8,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 7.0000,
"image": null
}, {
"id": 43189,
"text": "8",
"alias": null,
"position": 9,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 8.0000,
"image": null
}, {
"id": 43190,
"text": "9",
"alias": null,
"position": 10,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 9.0000,
"image": null
}, {
"id": 43191,
"text": "10",
"alias": null,
"position": 11,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": 10.0000,
"image": null
}],
"layout": "Horizontal",
"show_separator": false,
"option_width": null,
"question_text": "<p><span style=\"background-color: transparent; color: rgb(0, 0, 0);\">To what degree is the need described common in your research/work? (choose only one)</span></p>",
"subtext": "",
"is_required": true,
"item_position": "Left",
"question_text_position": "Top",
"id": 13275,
"item_type": "RadioButtonScale",
"page_id": 5292,
"position": 3,
"alias": "",
"html_class": null,
"include_condition": null
}, {
"script": "\n$(function() {\n localStorage.setItem('Speeder', new Date());\n $('.btn-next').hide();\n $('.btn-prev').hide();\n\n function BIO_showButton() {\n $('.btn-next').show();\n $('.btn-prev').show();\n }\n setTimeout(BIO_showButton, 5000);\n namespace.checkForSurveyComplete();\n});",
"id": 13276,
"item_type": "Javascript",
"page_id": 5292,
"position": 4,
"alias": null,
"html_class": null,
"include_condition": null
}]
The other array looks like this:
{{
"rows": [
{
"id": 1123,
"position": 1,
"row_type": "Normal",
"text": "First Row",
"alias": null,
"include_condition": {
"expressions": [],
"groups": [],
"logical_operator": "OR"
}
},
{
"id": 1124,
"position": 2,
"row_type": "Normal",
"text": "Second Row",
"alias": null,
"include_condition": {
"expressions": [],
"groups": [],
"logical_operator": "OR"
}
},
{
"id": 1125,
"position": 3,
"row_type": "Normal",
"text": "Thrid Row",
"alias": null,
"include_condition": {
"expressions": [],
"groups": [],
"logical_operator": "OR"
}
},
{
"id": 1126,
"position": 4,
"row_type": "Normal",
"text": "Fourth Row",
"alias": null,
"include_condition": {
"expressions": [],
"groups": [],
"logical_operator": "OR"
}
}
],
"columns": [
{
"id": 1079,
"position": 1,
"column_type": "RowTexts",
"prototype_item": null,
"require_unique_answers": false,
"width": 0
},
{
"id": 1080,
"position": 2,
"column_type": "Question",
"prototype_item": {
"layout": "Vertical",
"columns": 1,
"show_number_labels": false,
"choices": [
{
"id": 43713,
"text": "1st Radio Grid",
"alias": null,
"position": 0,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": null,
"image": null
},
{
"id": 43714,
"text": "2nd Radio Grid",
"alias": null,
"position": 1,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": null,
"image": null
},
{
"id": 43715,
"text": "3rd Radio Grid",
"alias": null,
"position": 2,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": null,
"image": null
},
{
"id": 43716,
"text": "4th Radio Grid",
"alias": null,
"position": 3,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": null,
"image": null
},
{
"id": 43717,
"text": "Last Radio Grid",
"alias": null,
"position": 4,
"is_default": false,
"is_other": false,
"is_none_of_above": false,
"points": null,
"image": null
}
],
"randomize": false,
"allow_other": false,
"question_text": "<p><span style=\"font-family: Lato;\">Select one of each</span></p>",
"subtext": "",
"is_required": false,
"item_position": "Left",
"question_text_position": "Top",
"id": 13516,
"item_type": "RadioButtons",
"alias": null,
"html_class": null,
"include_condition": null
},
"require_unique_answers": false,
"width": 0
}
],
"elements": [
{
"row": 1,
"column": 1,
"item": {
"text": "First Row",
"id": 13517,
"item_type": "Message",
"alias": null,
"html_class": null,
"include_condition": null
}
},
{
"row": 1,
"column": 2,
"item": {
"prototype_item_type": "RadioButtons",
"prototype_item_id": 13516,
"id": 13521,
"item_type": "MatrixQuestionColumnElement",
"alias": null,
"html_class": null,
"include_condition": null
}
},
{
"row": 2,
"column": 1,
"item": {
"text": "Second Row",
"id": 13518,
"item_type": "Message",
"alias": null,
"html_class": null,
"include_condition": null
}
},
{
"row": 2,
"column": 2,
"item": {
"prototype_item_type": "RadioButtons",
"prototype_item_id": 13516,
"id": 13522,
"item_type": "MatrixQuestionColumnElement",
"alias": null,
"html_class": null,
"include_condition": null
}
},
{
"row": 3,
"column": 1,
"item": {
"text": "Thrid Row",
"id": 13519,
"item_type": "Message",
"alias": null,
"html_class": null,
"include_condition": null
}
},
{
"row": 3,
"column": 2,
"item": {
"prototype_item_type": "RadioButtons",
"prototype_item_id": 13516,
"id": 13523,
"item_type": "MatrixQuestionColumnElement",
"alias": null,
"html_class": null,
"include_condition": null
}
},
{
"row": 4,
"column": 1,
"item": {
"text": "Fourth Row",
"id": 13520,
"item_type": "Message",
"alias": null,
"html_class": null,
"include_condition": null
}
},
{
"row": 4,
"column": 2,
"item": {
"prototype_item_type": "RadioButtons",
"prototype_item_id": 13516,
"id": 13524,
"item_type": "MatrixQuestionColumnElement",
"alias": null,
"html_class": null,
"include_condition": null
}
}
],
"grid_lines": "None",
"row_text_align": "Left",
"width": null,
"question_text": "<p><span style=\"font-family: Lato;\">This is the Grid Radio Question</span></p>",
"subtext": "",
"is_required": false,
"item_position": "Left",
"question_text_position": "Top",
"id": 13515,
"item_type": "Matrix",
"page_id": 5326,
"position": 1,
"alias": null,
"html_class": null,
"include_condition": null
}}
Notice how it is a two item array with quite difference values in each array element.
So, if I have a c# object that matches each of the objects in the array, how do I get JSON to deserialize each array element into their respective types? (There is a base type that has the item_type and text in it). I have this working:
object[] objValues = JsonConvert.DeserializeObject<object[]>(strJson, settings);
baseObject[] objBaseValues = JsonConvert.DeserializeObject<baseObject[]>(strJson, settings);
Then, I'm looking through the objBaseValues to find out which type and then re-converting each array element from the json object, like this:
List<baseObject> objReturn = new List<baseObject>();
for (int i = 0; i < objBaseValues.Length; i++)
{
if (objBaseValues[i].item_type.ToLower() == "matrix")
{
objReturn.Add(JsonConvert.DeserailizeObject<MatrixPageItem>(JsonConver.SerializeObject(objValues[i]), settings);
}
else
{
objReturn.Add(JsonConvert.DeserializeObject<PageItem>(JsonConvert.SerializeObject(objValues[i]), settings);
}
}
This is working, but is there a better way?
TIA,
Alright! This is probably going to be a long one xD So bear with me.
What I did to resolve this issue was create an object that implemented JsonConverter. What I did with this custom implementation was grab something inside the object that identified what type it was. And then activate the type that matched and called serializer.Populate(reader, instance) to pass the ball back to the default jsonconverter.
This is some of the code that I have in production:
I've written some instructions in the comments
public class JsonTypeIdBasedConverter : JsonConverter
{
public override bool CanWrite => false;
public override bool CanRead => true;
//I do not know what this needs to be for you. Because what happens is, the JsonConverter walks over the type specified in the generic parameter.
//It walks over its propertyTypes and passes that type on to this method to decide if this object was meant to parse for the type.
//So what I would suggest is you make a wrapper object representing the list, that has a list of items of type interface for the two or more objects that you want to parse to and decide here of the property is a list of that specific interface
//If you simply do return true, that will not work because then this object will also get called for every other type of parsing, you do not want that :)
public override bool CanConvert(Type objectType)
=> typeof(ResolvableByTypeId).IsAssignableFrom(objectType);
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
=> throw new InvalidOperationException("Use default serialization.");
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var jsonToken = JToken.Load(reader);
if (jsonToken.Type == JTokenType.Null)
return null;
//this for me was the identifying attribute in the json object that revealed what type is was for them, so I could grab our
string typeId = jsonToken["TypeId"].Value<string>();
object result = CreateObjectByTypeId(typeId);
serializer.Populate(jsonToken.CreateReader(), result);
return result;
}
private object CreateObjectByTypeId(string typeId)
{
... grab type from somewhere, list? switch?
return Activator.CreateInstance(typeToCreate);
}
}
Serializer.Populate then further walks over all properties of that newly instantiated object and recursively does what it normally does.
The interface then needs to have an attribute that labels it needs to be parsed using this converter type:
namespace SomeNamespace
{
[JsonConverter(typeof(JsonTypeIdBasedConverter))]
public interface Condition
{
bool Validate(Context context);
}
}
I've triple checked my code... I think that was all there is to it.
But if I am mistaken, please comment back and i'll run past it all again if this helps you! :)
-- PS:
I do not think that long ass comment in the code is quite transparent... So i'll try to shine some light on what I mean.
I have a class that has a list of type interface (1), since json does not know what concrete type it actually needs to resolve to, I label the interface with a tagging interface(2) and make a custom json converter(3) that recognizes the interface(4), but does know the types it needs to resolve to based on information in the json file.
(1)
public class Wrapper
{
List<AbstractItemType> _unknownType
}
(3)[JsonConverter(typeof(AbstractItemJsonConverter))]
(2)public Interface AbstractItemType : TaggingInterface {}
public Interface TaggingInterface {}
public class ConcreteItem1 : AbstractItemType
{
}
public class ConcreteItem2 : AbstractItemType
{
}
(3)
public class AbstractItemJsonConverter : JsonConverter
{
...
(4)
public override bool CanConvert(Type objectType)
=> typeof(TaggingInterface).IsAssignableFrom(objectType);
...
}

Distinct between two queries

I want to use distinct between food and rate.
i want that Food ID if exist in rate table as FID so skip that one I hope you understand my Problem.
var result = new
{
food = db.Foods.Where(q => idList.Contains(q.ID)),
rate = rates.Take(1).Distinct()
};
return Request.CreateResponse(HttpStatusCode.OK,result);
Look i am getting 3 food object and one rating object i want to skip that rating object whose FID already exist in food object i cannot elaborate further more i am sorry.
"food": [
{
"ID": 65,
"Name": "Grilled chicken",
"Price": "580",
"CatID": 75,
"UID": 101,
"Date_Time": "2019-04-01T00:00:00",
"FoodDescription": "Chicken with some oregeno",
"CookingTime": "25 min",
"Image": ,
"Uploadedby": "Hanzala Iqbal",
"Carts": [],
"Category": null,
"User": null,
"FoodRecommendations": [],
"OrderFoods": [],
"Ratings": []
},
{
"ID": 69,
"Name": "Lahori chargha",
"Price": "1000",
"CatID": 79,
"UID": 101,
"Date_Time": "2019-04-01T00:00:00",
"FoodDescription": "Garnish with some tomato sauce ",
"CookingTime": "2 hours",
"Image": ",
"Uploadedby": "Hanzala Iqbal",
"Carts": [],
"Category": null,
"User": null,
"FoodRecommendations": [],
"OrderFoods": [],
"Ratings": []
},
{
"ID": 70,
"Name": "Moroccon chicken",
"Price": "900",
"CatID": 80,
"UID": 101,
"Date_Time": "2019-04-01T00:00:00",
"FoodDescription": "chicken with green olives and lemon",
"CookingTime": "2.5 hour",
"Image": "",
"Uploadedby": "Hanzala Iqbal",
"Carts": [],
"Category": null,
"User": null,
"FoodRecommendations": [],
"OrderFoods": [],
"Ratings": []
}
],
"rate": [
{
"ID": 15,
"Rate": 5,
"FID": 65,
"UID": 102,
"Food": {
"ID": 65,
"Name": "Grilled chicken",
"Price": "580",
"CatID": 75,
"UID": 101,
"Date_Time": "2019-04-01T00:00:00",
"FoodDescription": "Chicken with some oregeno",
"CookingTime": "25 min",
"Image": "",
"Uploadedby": "Hanzala Iqbal",
"Carts": [],
"Category": null,
"User": null,
"FoodRecommendations": [],
"OrderFoods": [],
"Ratings": []
},
"User": null
}
]
var foodQuery = db.Foods.Where(row => idList.Contains(row.ID));
var rateQuery = db.Rates.Where(row => !foodQuery.Any(food => food.ID == row.FID)).Take(1);
var result = new
{
food = foodQuery,
rate = rateQuery
};
return Request.CreateResponse(HttpStatusCode.OK,result);
you can also use this one:
var result = db.Foods.Where(q => q.Rates.Any(x => x.FID != q.Id));

Handling double quotes in JSON strings

We have an application with knockout and we are facing a problem that some registers in the database have double quotes, which caused JSON parsing to fail.
Here's my json that is not valid due to a rogue double quote:
{
"OptionSummaries": [
{
"Id": 110,
"Name": "Option 1",
"Status": 1,
"ProductGroupNodes": [
{
"Id": 110,
"Name": "Corporate Brand Reputation",
"Status": 2,
"Waves": [
{
"Id": 110,
"Name": "Wave 1",
"Status": 2,
"Services": [
{
"Id": 1101,
"Title": "Proposal Budget Owner Service",
"CurrencyCode": "USD",
"EstimatedCost": 177.0000,
"CreationDateTime": "/Date(1437472898503)/",
"Status": 2
}
]
}
]
},
{
"Id": 111,
"Name": "2013 Consumer Scan",
"Status": 1,
"Waves": [
{
"Id": 111,
"Name": "Wave 1",
"Status": 1,
"Services": [
{
"Id": 1111,
"Title": "Proposal Budget Owner Service",
"CurrencyCode": "USD",
"EstimatedCost": 0.0000,
"CreationDateTime": "/Date(1437472898503)/",
"Status": 1
}
]
}
]
}
]
},
{
"Id": 115,
"Name": "Option 2",
"Status": 1,
"ProductGroupNodes": [
{
"Id": 115,
"Name": "Corporate Brand Reputation",
"Status": 1,
"Waves": [
{
"Id": 115,
"Name": "Wave 1",
"Status": 1,
"Services": [
{
"Id": 1151,
"Title": "Proposal Budget Owner Service",
"CurrencyCode": "USD",
"EstimatedCost": 0.0000,
"CreationDateTime": "/Date(1437472898503)/",
"Status": 1
}
]
}
]
},
{
"Id": 116,
"Name": "2013 Consumer Scan",
"Status": 1,
"Waves": [
{
"Id": 116,
"Name": "Wave 1",
"Status": 1,
"Services": [
{
"Id": 1161,
"Title": "Proposal Budget Owner Service",
"CurrencyCode": "USD",
"EstimatedCost": 0.0000,
"CreationDateTime": "/Date(1437472898503)/",
"Status": 1
}
]
}
]
}
]
}
],
"ServiceCostsEdit": {
"ServiceId": 1101,
"ServiceName": "Proposal Budget Owner Service",
"ServiceCurrencyIsoCode": "USD",
"ServiceLegalEntityCode": "0310",
"LaborHourCostsPanel": {
"LaborHourCosts": [
{
"Id": 2,
"CostCenters": [
{
"Disabled": false,
"Group": null,
"Selected": false,
"Text": "3101010001 - Consumer KAM Group",
"Value": "3101010001"
},
{
"Disabled": false,
"Group": null,
"Selected": false,
"Text": "3102510255 - Knowledge Panel",
"Value": "3102510255"
}
],
"FiscalYears": [
{
"Disabled": false,
"Group": null,
"Selected": false,
"Text": "2013",
"Value": "2013"
}
],
"LaborGrades": [
{
"Code": "0HL002",
"CurrencyCode": "USD",
"Rate": 44.0000,
"Disabled": false,
"Group": null,
"Selected": false,
"Text": "0HL002 - 44.00/hr USD",
"Value": "0HL002"
}
],
"SelectedLaborGradeCostCenter": "3101010001",
"SelectedLaborGradeFiscalYear": 2013,
"SelectedLaborGradeCode": "0HL002",
"SelectedLaborGradeRate": 44.0000,
"SetupHours": 2.00,
"ManagementHours": 1.00,
"DeliveryHours": 1.00,
"IsEmpty": false
}
],
"LaborHourCostsCostCenterDataSource": [
{
"Disabled": false,
"Group": null,
"Selected": false,
"Text": "3101010001 - Consumer KAM Group",
"Value": "3101010001"
},
{
"Disabled": false,
"Group": null,
"Selected": false,
"Text": "3102510255 - Knowledge Panel",
"Value": "3102510255"
}
],
"DefaultCostCenterCodeForInitialEmptyRecord": null,
"DefaultFiscalYearForInitialEmptyRecord": null,
"OverheadCosts": [
{
"LaborGradeCostCenterCode": "3101010001",
"LaborGradeFiscalYear": 2013,
"OverheadRate": 0.0000,
"SetupHours": 2.00,
"ManagementHours": 1.00,
"DeliveryHours": 1.00
}
],
"OverheadCostsVisible": true,
"OverheadCostsInitialDataSource": [
{
"Key": {
"CostCenterCode": "3101010001",
"FiscalYear": 2013
},
"Value": {
"Code": "0HO001",
"CurrencyCode": "USD",
"Rate": 0.00,
"Disabled": false,
"Group": null,
"Selected": false,
"Text": "0HO001 - USD 0.00/hr",
"Value": "0HO001"
}
}
],
"CostCenter": "F2F PAPI",
"ServiceCurrencyIsoCode": "USD",
"EditingAllowed": true
},
"VendorCostsPanel": {
"VendorCosts": [
{
"Id": 132,
"SelectedCostElementCode": "1992000004",
"VendorCode": "",
"VendorName": null,
"Description": "doublequotes"","DirectCostAttachment":null,"Quantity":1,"VendorRate":1.0000,"IsEmpty":false}],"CostElements":[{"Disabled":false,"Group":null,"Selected":false,"Text":"ExternalSuppliercosts","Value":"1992000004"},{"Disabled":false,"Group":null,"Selected":false,"Text":"Licensesfromaffilitatedcompanies","Value":"1992000002"}],"ServiceCurrencyIsoCode":"USD","EditingAllowed":true},"CostingAssumptionsPanel":{"Description":"","EditingAllowed":true},"ServiceSpecificationsPanel":{"Title":"ProposalBudgetOwnerService","Type":"ProposalBudgetOwnerService","Fields":[{"Value":"Hellolonglonglongtext...","Id":153,"Code":"OVERVIEW","Title":"Overview","IsRequiredForCosting":false,"DependencyVisibilityExpression":null,"FieldCodesToReevaluateOnChange":[],"EditingAllowed":false}]},"ApprovalComments":{"CommentType":0,"Message":null,"ApproverName":null,"ApproverEmail":null,"AnyComments":false},"RejectedCostInfoVisible":false,"EditingAllowed":true},"SubmitCostsEnabled":true,"EditingAllowed":false,"SelectedTreeNode":{"Id":1101,"Type":3},"Proposal":{"ProposalId":11,"ProposalName":"Ad-hocatCostingonMain","ProposalCostCenterCode":"3102510220","ProposalValid":{"IsValid":true,"ErrorMessage":""},"SoldToCustomer":"JenniferSamson","ExpectedProjectStartDate":"/Date(1426892400000)/","ExpectedProjectEndDate":"/Date(1431208800000)/","FunctionalityAreaEnabled":true}}
If you test this json against jsonlint you will see where the problem lies. What is the best way to handle this? I think the way I'm serializing the C# model to JSON is not proper? To do that I use:
var jsonModel = JsonConvert.SerializeObject(Model);
Any help is very appreciated.
EDIT
Issue was fixed. Problem was with the serialization.
I fixed this by using the method HttpUtility.JavaScriptStringEncode
var jsonViewModel = HttpUtility.JavaScriptStringEncode(Json.Encode(Model));
This solved my problem. All I had to do to pass this to knockout was #Html.Raw(jsonViewModel)
Best regards and thanks everyone!
Daniel

How to display JSON Data onto a UITableView

I am using Xamarin.iOS to return a JSON and attempt to place it on a UITableView, however I cannot seem to get it to work, here is what I am attempting to do so far:
Main View Controller
This is how I am returning the JSON
var request = new RestRequest {RootElement = "data", Resource = "/users/self/feed"};
request.AddParameter("access_token", instagramAccessToken);
var client = new RestClient ("https://api.instagram.com/v1");
// Edited Client Execution
client.ExecuteAsync(request, response =>
{
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(response.Content);
table.Source = new TableSource(rootObject.data);
table.ReloadData();
}
);
TableSource Class
public List<RootObject> Data { get; set; }
protected string cellIdentifier = "TableCell";
public TableSource ()
{
Data = new List<T> ();
}
public TableSource(List<T> data)
{
Data = data;
}
public override int RowsInSection (UITableView tableview, int section)
{
return Data.Count;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
if (OnRowSelected != null) {
OnRowSelected (this, new RowSelectedEventArgs (tableView, indexPath));
}
}
public class RowSelectedEventArgs : EventArgs
{
public UITableView tableView { get; set; }
public NSIndexPath indexPath { get; set; }
public RowSelectedEventArgs(UITableView tableView, NSIndexPath indexPath) : base()
{
this.tableView = tableView;
this.indexPath = indexPath;
}
}
public event EventHandler<RowSelectedEventArgs> OnRowSelected;
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
// if there are no cells to reuse, create a new one
if (cell == null)
cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
// Edited Text
cell.TextLabel.Text = ((Datum)Data[indexPath.Row]).user.username;
return cell;
}
I didn't really have a concrete method of displaying the JSON on the Table, so I would be pretty open to radical change. BTW the JSON loads on the MainViewController perfectly.
JSON Response
Most of your suggestions don't take into consideration how the JSON looks like so here you go:
{
"pagination": {
"next_url": "https://api.instagram.com/v1/users/self/feed?access_token=6489401.88b3fb2.7af2a0355ea24f4590efa1ee82ed0a49&max_id=668439962408115415_16915182",
"next_max_id": "668439962408115415_16915182"
},
"meta": {
"code": 200
},
"data": [
{
"attribution": null,
"tags": [
"selfie"
],
"type": "image",
"location": null,
"comments": {
"count": 0,
"data": []
},
"filter": "Normal",
"created_time": "1393953134",
"link": "http://instagram.com/p/lIO1_jmkkr/",
"likes": {
"count": 14,
"data": [
{
"username": "muahjay",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_304620904_75sq_1392618687.jpg",
"id": "304620904",
"full_name": "Jeanettee Nicole Cambero Gamez"
},
{
"username": "iam_mrsmith31",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_32806209_75sq_1392607367.jpg",
"id": "32806209",
"full_name": "Kiondrix Smith"
},
{
"username": "anniyalation",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_30752906_75sq_1390523572.jpg",
"id": "30752906",
"full_name": "Niya G."
},
{
"username": "fonzo_badmon",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_271402803_75sq_1393641486.jpg",
"id": "271402803",
"full_name": "Slimshady"
}
]
},
"images": {
"low_resolution": {
"url": "http://distilleryimage11.s3.amazonaws.com/e02592b0a3bf11e3b63212d269f676eb_6.jpg",
"width": 306,
"height": 306
},
"thumbnail": {
"url": "http://distilleryimage11.s3.amazonaws.com/e02592b0a3bf11e3b63212d269f676eb_5.jpg",
"width": 150,
"height": 150
},
"standard_resolution": {
"url": "http://distilleryimage11.s3.amazonaws.com/e02592b0a3bf11e3b63212d269f676eb_8.jpg",
"width": 640,
"height": 640
}
},
"users_in_photo": [],
"caption": {
"created_time": "1393953134",
"text": "#Selfie",
"from": {
"username": "kthompkins7",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_5941681_75sq_1378508674.jpg",
"id": "5941681",
"full_name": "kthompkins7"
},
"id": "668849828018145517"
},
"user_has_liked": false,
"id": "668849827690989867_5941681",
"user": {
"username": "kthompkins7",
"website": "",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_5941681_75sq_1378508674.jpg",
"full_name": "kthompkins7",
"bio": "",
"id": "5941681"
}
},
{
"attribution": null,
"tags": [
"rp",
"amen"
],
"type": "image",
"location": null,
"comments": {
"count": 5,
"data": [
{
"created_time": "1393949795",
"text": "#tmcmc Dobson a Christian!!!!",
"from": {
"username": "keelanwillison",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_26089241_75sq_1380511035.jpg",
"id": "26089241",
"full_name": "Keelanwillison"
},
"id": "668821819276579152"
},
{
"created_time": "1393950029",
"text": "Yo my cousin got me a singed autograph from you at the Boston boat show thanks man #a_dobson3",
"from": {
"username": "danthebigboy914",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_27354625_75sq_1393859632.jpg",
"id": "27354625",
"full_name": "Danny Chiappetta"
},
"id": "668823778033324461"
},
{
"created_time": "1393950659",
"text": "Amen",
"from": {
"username": "sandyrodr",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_44889389_75sq_1361591427.jpg",
"id": "44889389",
"full_name": "sandyrodr"
},
"id": "668829062428545715"
},
{
"created_time": "1393950664",
"text": "🙏",
"from": {
"username": "cherydaily",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_18483862_75sq_1379884114.jpg",
"id": "18483862",
"full_name": "Andrew \"Drew\" Chery"
},
"id": "668829109488636596"
},
{
"created_time": "1393951921",
"text": "Amen",
"from": {
"username": "bostonsonia",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_182219303_75sq_1391293289.jpg",
"id": "182219303",
"full_name": "Sonia"
},
"id": "668839648625348773"
}
]
},
"filter": "Normal",
"created_time": "1393949714",
"link": "http://instagram.com/p/lIIUdggtOj/",
"likes": {
"count": 324,
"data": [
{
"username": "bwest05",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_387702554_75sq_1393739891.jpg",
"id": "387702554",
"full_name": "💥bb💥"
},
{
"username": "babygirl6193",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_23365060_75sq_1384972330.jpg",
"id": "23365060",
"full_name": "babygirl6193"
},
{
"username": "derekmooney1",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_218356294_75sq_1388601101.jpg",
"id": "218356294",
"full_name": "Derek Mooney"
},
{
"username": "zay0613",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_342812999_75sq_1369576584.jpg",
"id": "342812999",
"full_name": "Zay"
}
]
},
"images": {
"low_resolution": {
"url": "http://distilleryimage11.s3.amazonaws.com/0e1b270aa3b811e395af12cdc849cb9b_6.jpg",
"width": 306,
"height": 306
},
"thumbnail": {
"url": "http://distilleryimage11.s3.amazonaws.com/0e1b270aa3b811e395af12cdc849cb9b_5.jpg",
"width": 150,
"height": 150
},
"standard_resolution": {
"url": "http://distilleryimage11.s3.amazonaws.com/0e1b270aa3b811e395af12cdc849cb9b_8.jpg",
"width": 640,
"height": 640
}
},
"users_in_photo": [],
"caption": {
"created_time": "1393949714",
"text": "#RP from #flashgoodwin #AMEN",
"from": {
"username": "a_dobson3",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_203045179_75sq_1374262647.jpg",
"id": "203045179",
"full_name": "a_dobson3"
},
"id": "668821135462420769"
},
"user_has_liked": false,
"id": "668821135110099875_203045179",
"user": {
"username": "a_dobson3",
"website": "",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_203045179_75sq_1374262647.jpg",
"full_name": "a_dobson3",
"bio": "",
"id": "203045179"
}
},
{
"attribution": null,
"tags": [
"tb12"
],
"type": "image",
"location": null,
"comments": {
"count": 169,
"data": [
{
"created_time": "1393952642",
"text": "My guy! The greatest! I just want him to get another ring so the haters can stop saying he hasn't won one since 04. I mean he still won them right? #TomBrady #patriots",
"from": {
"username": "k_aus32",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_39840771_75sq_1390431094.jpg",
"id": "39840771",
"full_name": "k_aus32"
},
"id": "668845703585318559"
},
{
"created_time": "1393952673",
"text": "#heres_jonni9",
"from": {
"username": "allyson21lautner",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_184895764_75sq_1393107648.jpg",
"id": "184895764",
"full_name": "Allyson 💌"
},
"id": "668845962264823470"
},
{
"created_time": "1393952694",
"text": "Let's go !",
"from": {
"username": "tom12terrific",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_421023272_75sq_1393644166.jpg",
"id": "421023272",
"full_name": "Andrew Estrada"
},
"id": "668846135581853361"
},
{
"created_time": "1393952856",
"text": "♡",
"from": {
"username": "in_neverland74",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_181245582_75sq_1391928288.jpg",
"id": "181245582",
"full_name": "Karen💕"
},
"id": "668847491935880949"
},
{
"created_time": "1393952914",
"text": "Follow for patriots pics daily!! (Ifollowback)",
"from": {
"username": "ne_patriots_fanpage__",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_983242248_75sq_1391989748.jpg",
"id": "983242248",
"full_name": "New England Patriots Fanpage"
},
"id": "668847980295472912"
},
{
"created_time": "1393952952",
"text": "Best ever; period. Let's see anyone win a ring with the humps he's had to work with, (except Randy).",
"from": {
"username": "calidoso76",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_1101426299_75sq_1392654362.jpg",
"id": "1101426299",
"full_name": "calidoso76"
},
"id": "668848301545604900"
},
{
"created_time": "1393953005",
"text": "Shit just because brady hasn't won a ring since 04 don't mean a thing....one more and he'll have 6.....the most superbowl wins than ANY quarterback EVER. #patriots",
"from": {
"username": "inkandartsosick",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_260242163_75sq_1363337609.jpg",
"id": "260242163",
"full_name": "Eric Hughes"
},
"id": "668848744304723771"
},
{
"created_time": "1393953023",
"text": "👈🏈🙌",
"from": {
"username": "bvsed_papi_",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_408657565_75sq_1393905141.jpg",
"id": "408657565",
"full_name": "Abel Valle™"
},
"id": "668848894913791811"
}
]
},
"filter": "Lo-fi",
"created_time": "1393949267",
"link": "http://instagram.com/p/lIHd-_v8Uj/",
"likes": {
"count": 13685,
"data": [
{
"username": "dollathebarber",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_219503241_75sq_1373905843.jpg",
"id": "219503241",
"full_name": "dollathebarber"
},
{
"username": "emastro23",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_21122956_75sq_1388823730.jpg",
"id": "21122956",
"full_name": "Eddie Mastrocola"
},
{
"username": "pat_fan99",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_304601453_75sq_1377084414.jpg",
"id": "304601453",
"full_name": "Timothy Smith"
},
{
"username": "___adam___q",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_3694047_75sq_1367384028.jpg",
"id": "3694047",
"full_name": "Adam Quinonez"
}
]
},
"images": {
"low_resolution": {
"url": "http://distilleryimage10.s3.amazonaws.com/1c67f514a3b711e383121299eef1f922_6.jpg",
"width": 306,
"height": 306
},
"thumbnail": {
"url": "http://distilleryimage10.s3.amazonaws.com/1c67f514a3b711e383121299eef1f922_5.jpg",
"width": 150,
"height": 150
},
"standard_resolution": {
"url": "http://distilleryimage10.s3.amazonaws.com/1c67f514a3b711e383121299eef1f922_8.jpg",
"width": 640,
"height": 640
}
},
"users_in_photo": [],
"caption": {
"created_time": "1393949267",
"text": "#tb12",
"from": {
"username": "patriots",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_1939080_75sq_1385924433.jpg",
"id": "1939080",
"full_name": "New England Patriots"
},
"id": "668817391815214218"
},
"user_has_liked": false,
"id": "668817391496447267_1939080",
"user": {
"username": "patriots",
"website": "",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_1939080_75sq_1385924433.jpg",
"full_name": "New England Patriots",
"bio": "",
"id": "1939080"
}
},
{
"attribution": null,
"videos": {
"low_resolution": {
"url": "http://distilleryimage4.s3.amazonaws.com/2cb7114aa3b511e3a3e312f545262070_102.mp4",
"width": 480,
"height": 480
},
"standard_resolution": {
"url": "http://distilleryimage4.s3.amazonaws.com/2cb7114aa3b511e3a3e312f545262070_101.mp4",
"width": 640,
"height": 640
}
}
}
]
}
After those two Edits I still have two errors:
Error on Main View Controller
Error on Table Source
No need to assign the Data multiple times. Assign the source once and then call ReloadData().
client.ExecuteAsync(request, response =>
{
var rootObject = JsonConvert.DeserializeObject<RootObject>(response.Content);
table.InvokeOnMainThread(() =>
{
table.Source = new TableSource(rootObject.data);
table.ReloadData();
});
}
);
EDIT: It seems there are four items in the Datum field and the last one is null.
https://github.com/sami1971/SimplyMobile/blob/master/iOS/Samples/TwitterSample/Twitter.cs
ToString() override for Datum:
public override string ToString()
{
if (user == null)
{
return "User is null";
}
return user.full_name;
}
For full sample download the project, open iOS/SimplyMobile.iOS.sln and run Samples/TwitterSample.
You should be able to do something like this:
cell.TextLabel.Text = ((Datum)Data[indexPath.Row]).user.username;
you have to reload tableView when all data retrived from url to your dictionary or array.
you can do this like this
[self.Yourtableview reloadData];

Categories