I am developing an app for iOS using Xamarin Studio (C#) in Mac OS X. I want to get a list of the user's friends on Facebook, so I added Facebook's component from Xamarin's component store and made a request(code at the bottom). This is the response I get:
{
data = (
{
"first_name" = Dev;
id = 100001438778777;
"last_name" = Accu;
}
);
paging = {
next = "https://graph.facebook.com/v2.0/100005203000814/friends?fields=id,first_name,last_name&format=json&access_token=CAAK3hGOIm2ABANPUcr2QU1t8gqLNsZCJBrc8ZCZCqUSwHkX2f43VHarvc1ZABbjDrY7jIO0OT5ZBRBiZC1audQnIvxCsOu60y30iR84jVa56beNTptixj7AFqT92ZBGdyxDshFHHxkFDgCg9JyRZBYfqaGKkeJkuxJVUXDq8eR8ZCmRlslpOVSavQZC1hCcxOwdgFS2jWQdGZBFVSYTkrhkavfP&limit=5000&offset=5000&__after_id=enc_Aey-LjP59ZnmKMcZKcEr94tTUPIHIvWj9JnMwkIVSvxJ9RBYBqhBt3bGKlURY4SHBCDeH8BM_wSsqICzEFgKiZvh";
};
}
There is 2 problems with this response, it only includes 1 friend for some unknown reason, and the JSON is not valid, so ultimately parsing this fails. The following is the code I use to make the request:
var friendsRequest = await new FBRequest(FBSession.ActiveSession, "/me/friends?fields=id,first_name,last_name").StartAsync();
var friendsArray = friendsRequest.Result as MonoTouch.Foundation.NSMutableDictionary;
var response = FriendResponse.FromJson(friendsArray.ToString());
List<FacebookProfile> friends = new List<FacebookProfile>();
foreach (var friend in response.Data)
{
friends.Add(new FacebookProfile(friend.ID, friend.FirstName, friend.LastName));
}
And here is the parsing classes:
public class NextPage
{
public string Next { get; set; }
}
public class Friend
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class FriendResponse
{
public List<Friend> Data { get; set; }
public NextPage Paging { get; set; }
public static FriendResponse FromJson(string json)
{
JsConfig.EmitLowercaseUnderscoreNames = true;
return JsonSerializer.DeserializeFromString<FriendResponse>(json);
}
}
The component is a 1:1 binding to the objective-c SDK. The response that Facebook returns is an NSDictionary underneath, and if you run ToString() on it, it will return the string representation of the NSDictionary which is totally different from a JSON
string. What you have to do is serialize that NSDictionary object back into a JSON string. Here is an example of how to do this:
var friendsRequest = await new FBRequest(FBSession.ActiveSession, "/me/friends?fields=id,first_name,last_name").StartAsync();
// Convert back the object into a Json
NSError error;
var jsonData = NSJsonSerialization.Serialize (friendsRequest.Result, 0, out error);
var jsonString = (string) NSString.FromData (jsonData, NSStringEncoding.UTF8);
var response = FriendResponse.FromJson(jsonString);
"jsonString" will have the correct JSON string data representation this time.
Courtesy of Alex DeSoto. =)
Related
I am calling SendGrid's Email Activity API using the RestSharp RestClient and it is properly returning data via a standard JSON response.
However, I'd like to deserialize that into a C# object since it would be much easier to work with than a raw JSON string. So I created a C# class that has public properties for each field in the JSON response, and gave them annotations with the exact name of the JSON fields.
But when I call JsonDeserializer().Deserialize>(response), while there's no error/exception, all of the fields in the objects are NULL.
Any ideas what's wrong? (You can just take out the "EventType" references as it's not really relevant here). Relevant code is below.
I'm using RestSharp v106.6.10.0 and Newtonsoft.Json v9.0.0.0 (the latter probably older but that's the library we normally use).
Project is .NET v4.6.1
private void QuerySendGridForEmailActivity(EventType eventType)
{
string query = string.Empty;
RestClient client = null;//new RestClient(emailActivityEndpoint);
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer " + apiKey);
request.AddParameter("limit", "1000");
if (eventType == EventType.Opens)
{
// request.AddParameter("query", WebUtility.UrlEncode("(Contains(events,\"open\"))"));
client = new RestClient(emailActivityEndpoint + "?limit=10&query=" + System.Web.HttpUtility.UrlPathEncode("(Contains(events,\"open\"))"));
}
IRestResponse response = client.Execute(request);
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
this.emailActivityEvents = new JsonDeserializer().Deserialize<List<EmailActivityEvent>>(response);
int i = 0;
}
else
{
}
}
public class EmailActivityEvent
{
[DeserializeAs(Name = "from_email")]
public string FromEmail { get;set; }
[DeserializeAs(Name = "msg_id")]
public string MessageId { get; set; }
[DeserializeAs(Name = "subject")]
public string Subject { get; set; }
[DeserializeAs(Name = "to_email")]
public string ToEmail { get; set; }
[DeserializeAs(Name = "status")]
public string Status { get; set; }
[DeserializeAs(Name = "opens_count")]
public int OpensCount { get; set; }
[DeserializeAs(Name = "clicks_count")]
public int ClicksCount { get; set; }
[DeserializeAs(Name = "last_event_time")]
public DateTime LastEventTime { get; set; }
}
Ok, I should've gotten this earlier but I didn't think I needed to do this.
I had to add another class that I named "EmailActivity" that just has a List<> of the email events, with a deserialize annotation matching the actual name of the item in JSON. Like this:
public class EmailActivity
{
[DeserializeAs(Name = "messages")]
public List<EmailActivityEvent> Events { get; set; }
}
Then just adjust the deserialize call slightly to this:
var emailActivity = new JsonDeserializer().Deserialize<EmailActivity>(response);
And that did it. Duh.
Just FYI, the JSON being returned was in this format:
{"messages":
[{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-26T20:30:02Z"
},
{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-26T20:30:01Z"
},
{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-25T22:06:25Z"
}
]}
Thanks for your comments!
I am calling a REST service from my C# application which connects to CRM.
This returns HttpResponseMessage.
response.Content.ReadAsStringAsync().Result
The above statement returns following output. I need to convert this to Account object, which already has "accountnumber, and accountid properties.
{
"#odata.context":"https://APIURL/api/data/v8.1/$metadata#account(accountnumber)","value":[
{
"#odata.etag":"W/\"12496866\"","accountnumber":"D00208","accountid":"30417c0f-7b8c-e611-80f3-5065f38bd4d1"
} ] }
I have tried following code
Account return = JsonConvert.DeserializeObject<Account>(response.Content.ReadAsStringAsync().Result);
But this doesn't fill up the object, and it always has null values in accountnumber, and accountid fields.
Any idea of how to properly convert this response to the C# type.
you should do it like this -
public class Value
{
[JsonProperty("#odata.etag")]
public string etag { get; set; }
public string accountnumber { get; set; }
public string accountid { get; set; }
}
public class RootObject
{
[JsonProperty("#odata.context")]
public string context { get; set; }
public List<Value> value { get; set; }
}
then deserialize-
var value = JsonConvert.DeserializeObject<RootObject>(json);
We can parse and create Anonymous Type based on that. In your case, replace the Anonymous Type with Account object.
Given the JSON string:
string json = #"{
'#odata.context':'https://APIURL/api/data/v8.1/$metadata#account(accountnumber)',
'value':[
{
'#odata.etag':'W/\'12496866\'',
'accountnumber':'D00208',
'accountid':'30417c0f-7b8c-e611-80f3-5065f38bd4d1'
}
]
}";
It can be parsed as below:
var jsonObject = JObject.Parse(json);
var dataObject = new
{
Context = jsonObject["#odata.context"],
Values = jsonObject["value"].AsEnumerable<JToken>()
.Select(v => new
{
ETag = v["#odata.etag"],
AccountNumber = v["accountnumber"],
AccountId = v["accountid"]
}).ToArray()
};
In order to convert to Account object where the object is defined as below:
public class Account
{
public string Number { get; set; }
public string Id { get; set; }
}
Then the JSON object can be parsed as below (if looking for only first node; It can also be converted to list of Accounts:
var jsonObject = JObject.Parse(json);
var account = jsonObject["value"].AsEnumerable<JToken>()
.Select(v => new Account()
{
Number = v["accountnumber"].ToString(),
Id = v["accountid"].ToString()
}).FirstOrDefault();
You can generalize the accepted answer by using a generic class to deserialize json web response:
class RootObject<T>
{
public List<T> Value { get; set; }
}
var odata = JsonConvert.DeserializeObject<RootObject<POCO>>(json);
Try it with live Demo
I am learning for the first time how to get a json file from a third party vendor and I am trying to do such with steam. I am trying to retrieve game name and play time of a specific game for a specific user. Based on the online documentation I have read the following code should be working, but the problem is that I am getting back a null. If I take the generated URL and put it in the browser I get back results which means my URL is good, but the way I am parsing it is wrong.
public class SteamMemberViewModel
{
public List<SteamGameViewModel> games { get; set; }
}
public class SteamGameViewModel
{
public int appid { get; set; }
public string name { get; set; }
public int playtime_forever { get; set; }
}
private string GetSteamGame()
{
const int rocketLeagueId = 252950;
var format = string.Format("http://api.steampowered.com/{0}/{1}/v{2}/?key={3}&steamid={4}&include_appinfo=1&format=json", "IPlayerService", "GetOwnedGames", "0001", "ABC", "123");
using (WebClient wc = new WebClient())
{
var json = JsonConvert.DeserializeObject<SteamMemberViewModel>(wc.DownloadString(format));
var rocketLeage = json.games.Where(g => g.appid == rocketLeagueId);
var steamGameViewModels = rocketLeage as SteamGameViewModel[] ?? rocketLeage.ToArray();
if (steamGameViewModels.Count() == 1)
{
var playtime = steamGameViewModels.First().playtime_forever;
return steamGameViewModels.First().name + " - " + playtime;
}
}
return "Steam Game Not Found";
}
The error that I Get is
Value cannot be null.
Parameter name: source
Line 26: var json = JsonConvert.DeserializeObject(wc.DownloadString(format));
Line 27:
Line 28: var rocketLeage = json.games.Where(g => g.appid == rocketLeagueId);
Line 29: var steamGameViewModels = rocketLeage as SteamGameViewModel[] ?? rocketLeage.ToArray();
Line 30: if (steamGameViewModels.Count() == 1)
Source File: e:_websites\Local\Projects\Azularis\Azularis.System.Events\Azularis.System.Events\Controllers\HomeController.cs Line: 28
EDIT:
I have also tried running the code as follows:
var result = wc.DownloadString(format);
var data = JsonConvert.DeserializeObject<SteamMemberViewModel>(result);
var count = data.games.Count();
return count.ToString();
And I still got the same error. result comes back with values though.
JSON FILE EXAMPLE:
{
"response": {
"game_count": 16,
"games": [
{
"appid": 10,
"name": "Counter-Strike",
"playtime_forever": 5019,
"img_icon_url": "6b0312cda02f5f777efa2f3318c307ff9acafbb5",
"img_logo_url": "af890f848dd606ac2fd4415de3c3f5e7a66fcb9f",
"has_community_visible_stats": true
}
]
}
}
Value games inside SteamMemberViewModel is always null.
I would think your issue is that your top object in the JSON is response but you are trying to parse that into the equivalent of the games array. I would think you need to get the array object and then parse so you need to go down a level into the JSON object.
I can't be sure as you do not know if that serializer is performing some recursive work until it finds the object (I doubt it though) but the docs does not seem to do so:
http://www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm
in the example, it clearly states you need to get down to the object you mean to be your top level. And it is not response in your example.
So you'd have to do something like (pseudo-code):
JObject json = JObject.Parse(jsonString);
IList<JToken> array = json["response"]["games"].Children().ToList();
if(array != null)
{
var data = JsonConvert.DeserializeObject<SteamMemberViewModel>(array.ToString());
}
I know you already have an accepted answer. Your issue is easily fixable. Replace SteamMemberViewModel code with below code.
public class SteamMemberViewModel
{
public Response response { get; set; }
}
public class Response
{
public int game_count { get; set; }
public Game[] games { get; set; }
}
public class Game
{
public int appid { get; set; }
public string name { get; set; }
public int playtime_forever { get; set; }
public string img_icon_url { get; set; }
public string img_logo_url { get; set; }
public bool has_community_visible_stats { get; set; }
}
i use RestSharp to access a Rest API. I like to get Data back as an POCO.
My RestSharp Client looks like this:
var client = new RestClient(#"http:\\localhost:8080");
var request = new RestRequest("todos/{id}", Method.GET);
request.AddUrlSegment("id", "4");
//request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
//With enabling the next line I get an new empty object of TODO
//as Data
//client.AddHandler("*", new JsonDeserializer());
IRestResponse<ToDo> response2 = client.Execute<ToDo>(request);
ToDo td=new JsonDeserializer().Deserialize<ToDo>(response2);
var name = response2.Data.name;
my Class for the JsonObject looks like this:
public class ToDo
{
public int id;
public string created_at;
public string updated_at;
public string name;
}
and the Json Response:
{
"id":4,
"created_at":"2015-06-18 09:43:15",
"updated_at":"2015-06-18 09:43:15",
"name":"Another Random Test"
}
Per the documentation, RestSharp only deserializes to properties and you're using fields.
RestSharp uses your class as the starting point, looping through each
publicly-accessible, writable property and searching for a
corresponding element in the data returned.
You need to change your ToDo class to the following:
public class ToDo
{
public int id { get; set; }
public string created_at { get; set; }
public string updated_at { get; set; }
public string name { get; set; }
}
I have the following JSON stored in a cookie that I wish to parse:
{"package":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"}], "hotel":[{"id":"3421","nodeId":"1234"},{"id":"8748","nodeId":"2435"}], "activity":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"},{"id":"2131","nodeId":"2342"}]}
I understand from the accepted answer on this question Deserializing JSON to .NET object using Newtonsoft (or LINQ to JSON maybe?) that you can use the following code to access individual objects within JSON notation:
JToken token = JObject.Parse(stringFullOfJson);
int page = (int)token.SelectToken("page");
int totalPages = (int)token.SelectToken("total_pages");
I've therefore adapted this into my code as follows:
HttpCookie cookie = Request.Cookies.Get("wishlist");
string JSONstring = string.Empty;
string nodeId = string.Empty;
if (cookie != null)
{
JSONstring = cookie.Value;
JToken token = JObject.Parse(JSONstring);
}
I now wish to only retreive the package array for example and loop through each of the items in this array and output the ids in the following format:
5054,8888
From the example code I sort of came up with the following approach but i'm not sure if i'm proceeding in the right direction.
JObject obj = JObject.Parse(JSONstring);
JArray packages = (JArray)obj["package"];
What is the best way of specifying one of the arrays eg. hotel, package , looping through their contents and outputting each of the id nodes that are found? The nodeId will always be numeric but the id could be a string or an int so this adds another layer of complication.
Any help would be greatly appreciated and I apologise if this is a sumwhat stupid or easy question however I have jsut started working with .Net and OO so some of the concepts are still a bit foggy.
Here's How I would Do This, I'd Create the classes required to Deserialize the JSON :-
public class JSONCookie
{
public Package[] package { get; set; }
public Hotel[] hotel { get; set; }
public Activity[] activity { get; set; }
}
public class Package
{
public string id { get; set; }
public string nodeId { get; set; }
}
public class Hotel
{
public string id { get; set; }
public string nodeId { get; set; }
}
public class Activity
{
public string id { get; set; }
public string nodeId { get; set; }
}
Now, I would Create a method that actually does the deserialising :-
public JSONCookie GetJSONCookieResponse()
{
try
{
// Add your own code that gets the Response Here.
// string response = "{"package":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"}], "hotel":[{"id":"3421","nodeId":"1234"},{"id":"8748","nodeId":"2435"}], "activity":[{"id":"5054","nodeId":"3286"},{"id":"8888","nodeId":"7777"},{"id":"2131","nodeId":"2342"}]}";
//return new JsonSerializer().Deserialize<JSONCookie>(new JsonTextReader(new StringReader(response)));
}
catch
{
return null;
}
}
From the JSONCookie Object that is returned, you can then use LINQ to pick out what you need like follows :-
x.package.Select(p=>p.id);
After a lot of trawling Google, this is the easiest solution I have come up with:
HttpCookie cookie = Request.Cookies.Get("wishlist");
string JSONstring = string.Empty;
string nodeId = string.Empty;
string test = string.Empty;
if (cookie != null)
{
JSONstring = cookie.Value;
JObject obj = JObject.Parse(JSONstring);
JArray packages = (JArray)obj["package"];
foreach (var item in packages.Children()){
var properties = item.Children<JProperty>();
var idElement = properties.FirstOrDefault(x => x.Name == "id");
var myElementValue = idElement.Value;
test = test + myElementValue + ",";
}
}
This will output all ids in the packages array in a CSV format (with a trailing ,)