I'm trying to display the # of "likes" of a user selected entity that has a facebook site. The url that's passed in is the entities facebook name:
public int GetLikes(string url)
{
string jsonString = new WebClient().DownloadString("http://graph.facebook.com/?ids=" + url);
Dictionary<string, dynamic> values = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(jsonString);
int keyValues = values.Count;
int likes = values["likes"];
return likes;
}
I get an error that "likes" is not found in the value. But it's clearly there. Below is a sample of the JSON data that's returned from facebook:
{
"disney": {
"about": "\"It's kind of fun to do the impossible.\" - Walt Disney",
"category": "Company",
"checkins": 26,
"description": "This Page is a place for our Fans. However, we do need to have certain rules. Please be aware that we do not accept or consider unsolicited idea submissions and, also, we must reserve the right to remove any posting or other material that we find off-topic, inappropriate or objectionable.",
"founded": "1923",
"is_published": true,
"talking_about_count": 543991,
"username": "Disney",
"website": "http://disney.com",
"were_here_count": 0,
"id": "11784025953",
"name": "Disney",
"link": "http://www.facebook.com/Disney",
"likes": 46622418,
"cover": {
"cover_id": "10152010506970954",
"source": "http://sphotos-d.ak.fbcdn.net/hphotos-ak-prn1/t1.0-9/s720x720/1960125_10152010506970954_1312297640_n.png",
"offset_y": 0,
"offset_x": 0
}
}
}
I have tried many different things. Getting and deserializing the JSON data isn't a problem but I haven't been able to find a way to get any of the elements. Any help is appreciated.
First Create a class that mimics your JSON string (object) structure:
public class JSONobject
{
public Disney = new Disney();
}
public class Disney
{
public string about { get; set; }
public string category{get;set;}
public int checkins = {get;set;}
........
public int likes = {get;set;}
........
public Cover = new Cover();
}
public class Cover
{
public int cover_id { get;set; }
........
}
Then, initialize the object as well as the serializer:
JSONobject jsonOb = new JSONobject();
JavaScriptSerializer serializer = new JavaScriptSerializer();
Finally, parse the jsonString into your defined class:
try
{
jsonOb = serializer.Deserialize<JSONobject>(jsonString);
//ViewBag.jsondecoded = "Yes";
}
catch (Exception e)
{
//ViewBag.jsonDecoded = "No" + ", Exception: " + e.Message.ToString();
}
Retrieving variables:
string about = jsonOb.Disney.about;
string category = jsonOb.Disney.category;
int checkins = jsonOb.Disney.checkins;
int likes = jsonOb.Disney.likes;
Cover cover = jsonOb.Disney.Cover;
Hope this helps.
Related
[
{
"articles": [
[
"2016-03-04",
6
],
[
"2016-03-05",
10
],
[
"2016-03-06",
11
]
],
"accession": "00000446-201301000-00018"
},
{
"articles": [
[
"2016-03-04",
1
],
[
"2016-03-08",
17
],
[
"2016-03-09",
10
]
],
"accession": "00000446-201301000-00019"
}]
List is input { "Accession"= "00000446-201301000-00018", "Date"= "635926464000000000","Rank" =2},{ "Accession" = "00000446-201301000-00019", "Date" = "635931648000000000","Rank" = 2}
I want json data exactly like this,data is coming from list and list is dynamically growing.Form list, I want all dates and rank club to gether for the same accession number.
I want to use newtonsoft json custom serlization to convert my list to json.
What you want to do does not need any Custom Formatter, you just have to re-structure your data, Here is an example for restructuring a list based on Entity class to the new required one.
class Entity
{
public string Accession { get; set; }
public string Date { get; set; }
public int Rank { get; set; }
}
Add this line if you need to read the list from Json
var list = JsonConvert.DeserializeObject<List<Entity>>(input);
Here is the code for changing the structure of data to array based articles.
var translatedAsArray = list.GroupBy(e => e.Accession)
.Select(g =>
new {
//change new 'object[]' to 'new' to make the article an object
//you can convert i.Date, i.Rank and g.Key to anything you want here
Articles = g.Select(i => new object[] { i.Date , i.Rank }),
Accessing = g.Key
}
);
var json = JsonConvert.SerializeObject(translatedAsArray, Formatting.Indented);
Model
public class FinalList
{
public string accession {get;set;}
public List<ArticlesDetails> Articles{get;set;}
}
public class ArticlesDetails
{
public DateTime Date{get;set;}
public int number{get;set;}
}
Use ObjectContent instead of StringContent so we let the formatter (i.e. JsonMediaTypeFormatter) to deal with the serialization and deserialization
In config
config.Formatters.Insert(0, new YourCustomFormatter());
config.Formatters.Insert(1, new JsonMediaTypeFormatter());
and disable post in your custom formatter so that JsonMediaTypeFormatter desrializes the complex data
I have a query where I want only Id and name of the collection back to reduce the network traffic. I am able to get what i want from the database with the following part of the query
ShipToCities = Return.As<IEnumerable<string>>("COLLECT( [shipTo.InternalId, shipTo.Name])")
but the issue is i get back the data like this:
[ [ "IN.KA.MANG", "Mangalore" ], [ "IN.KA.MANG", "Mangalore" ], [ "IN.KA.BANG", "Bangalore" ] ]
but how can I map it to a C# object like
public class CityFound
{
public string CityId { get; set; }
public string CityName { get; set; }
}
is there a way to use some converter to achieve this without me having to use some ugly string manipulation myself?
UPDATE 1:
Actually my query is fairly complex and only way to get the data that I can think of is to handcraft the query like below to reduce the :
//selectedLoadQuery below is a complex query based on user selection...
var query = selectedLoadQuery
.Match("(load)-[:SHIPPED_BY]->(shipper)-[r:HAS_TRANSPORTER]->(transporter)")
.With("load, transporter, shipper, user, count(DISTINCT r) as MyClients")
.Match("p=(shipFrom:City)<-[:SHIP_FROM_CITY]-(load)-[:SHIP_TO_CITY]->(shipTo:City)")
.With("p, load, shipFrom, shipTo, transporter, MyClients")
.Return((load, shipFrom, shipTo) => new
{
TotalShipments = load.CountDistinct(),
FromMyClients = Return.As<long>("MyClients"),
ShipFromCities = Return.As<IEnumerable<string>>("COLLECT( [shipFrom.InternalId, shipFrom.Name])"),
ShipToCities = Return.As<IEnumerable<string>>("COLLECT( [shipTo.InternalId, shipTo.Name])"),
});
Regards
Kiran
You don't need to get so creative. You're only getting into this issue because you're hand crafting such a complex query that flattens out the structure of the data.
Create a class that describes what's in the node:
public class ShippingDestination
{
public long InternalId { get; set; }
public string Name { get; set; }
}
Use this to light up the following syntax in your Return statement:
var cities = graphClient
.Match(...)
.Return(shipTo => new {
Id = shipTo.As<ShippingDestination>().InternalId,
Name = shipTo.As<ShippingDestination>().Name,
})
.Results;
I've been playing around with asp.net web api, and I noticed that default generated returned json doesn't include the object level key. I was also wondering how to customize the output of the json string. For example:
Getting a User usually returns
{
"Name": "ChaoticLoki",
"Age": 22,
"Sex": "Male"
}
I was hoping I could return something like:
{
"data": {
"Name": "ChaoticLoki",
"Age": 22,
"Sex": "Male",
},
"success": true
}
You can then create a class wrapping the data and status like this
public class JsonResult{
public object data { get; set;}
public boolean success { get; set;}
}
And then in your Web Api methods, you can do
var data = ... //getting from repo
return Json(new JsonResult{data = data, success = true});
The first line of my action is tested with an extra integration test.
The second line is tested with an extra unit test for automapper mapping stuff
The third line is untested then.
The below unit test does it test the third line? because it just tests the return type.
This seems stupid or too trivial too me. What else should the method return????
There is no if/else logic inside this action. Therefore just testing for type == JsonNetResult seems superfluid for me. I would not even realize in my unit test if someone removes the success = true anonymous type.
Should I rather test the data of the JsonNetResult with QUnit?
I would be glad about some guidance and tips because the actions returning Json data drive me crazy... Its just fetch data from db and put it inside the JsonNetResult object.
Action
[HttpGet]
public ActionResult GetTemplateRootUnits(int templateId)
{
IEnumerable<Unit> units = _dataProvider.GetTemplateRootUnits(templateId);
IEnumerable<UnitTreeViewModel> unitTreeViewModels = Mapper.Map<IEnumerable<Unit>, IEnumerable<UnitTreeViewModel>>(units);
return new JsonNetResult(new { data = unitTreeViewModels, success = true });
}
Unit test
[Test]
public void GetTemplateRootUnits_TemplateExists_ReturnsJsonNetResult()
{
// ARRANGE
Mock<IUnitDataProvider> mock1 = new Mock<IUnitDataProvider>();
Mock<IMappingEngine> mock2 = new Mock<IMappingEngine>();
Mock<ControllerContext> mock3 = new Mock<ControllerContext>();
UnitController controller = new UnitController(mock1.Object, mock2.Object);
mock1.Setup(m => m.GetTemplateRootUnits(1)).Returns(new List<Unit>
{
new Unit{ UnitId = 1, Name = "Name1", HasChildren = false},
new Unit{ UnitId = 2, Name = "Name2", HasChildren = false},
new Unit{ UnitId = 3, Name = "Name3", HasChildren = false},
});
var unitTreeViewModels = new List<UnitTreeViewModel>
{
new UnitTreeViewModel { Id = 1, Name = "Name1", HasChildren = false},
new UnitTreeViewModel { Id = 2, Name = "Name2", HasChildren = false},
new UnitTreeViewModel { Id = 3, Name = "Name3", HasChildren = false},
};
// Thats the way AutoMapper is mocked
mock2.Setup(m => m.Map<IEnumerable<Unit>, IEnumerable<UnitTreeViewModel>>(It.IsAny<IEnumerable<Unit>>())).Returns(unitTreeViewModels);
// ACT
ActionResult result = controller.GetTemplateRootUnits(1);
// ASSERT - check that the dataProvider.GetTestplanRootUnits() was called
mock1.Verify(m => m.GetTemplateRootUnits(1));
// ASSERT
Assert.IsInstanceOfType(typeof(JsonNetResult), result);
}
JsonNetResult.cs
public class JsonNetResult : ContentResult
{
private readonly object _data;
public JsonNetResult(object data)
{
_data = data;
}
public override void ExecuteResult(ControllerContext context)
{
Content = JsonConvert.SerializeObject(_data);
ContentType = "application/json";
base.ExecuteResult(context);
}
public object Data { get { return _data; } }
}
You haven't shown what the JsonNetResult class is, but I will assume that it is some custom action result using JSON.NET as serializer instead of the default JavaScriptSerializer. I will also assume that this class exposes a public property of type object called Data holding the model that is to be serialized:
public class JsonNetResult: ActionResult
{
public JsonNetResult(object data)
{
Data = data;
}
public object Data { get; private set; }
...
}
So you could test the data inside the result:
// ASSERT
Assert.IsInstanceOfType(typeof(JsonNetResult), result);
var jsonResult = result as JsonNetResult;
var data = new RouteValueDictionary(jsonResult.Data);
Assert.IsTrue((bool)data["success"]);
Assert.IsInstanceOfType(data["data"], typeof(IEnumerable<UnitTreeViewModel>));
Assert.AreEqual(unitTreeViewModels, data["data"]);
You don't need to test type of return value. You need to set type of return value in signature of method.
public JsonNetResult GetTemplateRootUnits(int templateId);
Edit: I've got the solution and have described it a bit more at the end of the post
Using: MVC 3, C#
Problem: A key/value obj array sent to controller via $.post/$.ajax results in a 500 internal server error at the controller (because the value passed to the method in the C# controller is null)
I have an array that's in the format:
{
"q_1": {
"qid": "1",
"tmr": 0
},
"q_2": {
"qid": "2",
"tmr": 0
}
}
I get this via $("#myid").data() - and this is all fine.
I need to send this to my controller, and tried both post and $.ajax
var d = $("#q_data").data();
$.post("/run/submit", d, function(data) { alert(data);}, "application/json");
and
$.ajax({
url: '/run/submit',
data: d,
contentType: 'application/json',
dataType: 'json',
success: function (data) { alert(data); }
});
The method on the C# side is
public ActionResult Submit(List<PerfObj> dict)
{
int x = dict.Count;
return PartialView("_DummyPartial");
}
Where PerfObj is my model
public class PerfObj
{
public string id { get; set; }
Perfvar perfVar;
}
public class PerfVar
{
public string qid { get; set; }
/* note I've tried both int and string for the tmr param */
public string tmr { get; set; }
}
When I execute this, the call goes to the controller correctly - i.e. it hits the submit method. However, the method parameter dict, in
List<PerfObj> dict
is null.
Why? It seems to be something with my model, can't figure out how else to design it so it extracts the values correctly to the method parameter.
When I print the JSON.Stringify on the console, it shows the key/value pair correctly so I'm thinking it's going correctly to the server but the server/MVC3 doesn't like it for some reason or can't map it to the List of PerfObjs.
EDIT: Solution
Maciej's answer to my post was how I solved it. What I did eventually was to create a arrays of perfObj at the client side
$("#q_data").data(e,{key: e, perfVar: { qid: e, tmr: 0 }})
(ps - ignore redundant usage of 'e', I've got other plans, this is a dummy case)
And then I mapped it to a JSON friendly array
var arr = [];
$.each($('#q_data').data(), function (i, e) {
var p = $(this).data(i);
var obj = { key: i, perfVar: { id: e.perfVar.qid, tmr: e.perfVar.tmr}};
arr.push(obj);
});
Then stringified it
var q = JSON.stringify(arr);
$.ajax'd it as described in Maciej's post.
I redefined my classes properly
public class PerfObj
{
public string key { get; set; }
public PerfVar perfVar { get; set; }
}
public class PerfVar
{
public string id { get; set; }
public int tmr { get; set; }
}
and changed the signature of my controller method
[HttpPost]
public ActionResult Submit(PerfObj[] dict)
{
return PartialView("_DummyPartial");
}
This now works perfectly and I can extend my classes fairly easily to do what I want.
Thank you all!
There are 3 things wrong with your code:
A. The property PerfVar must be made public and there must be a get and set on it:
public class PerfObj
{
public string id { get; set; }
public Perfvar perfVar { get; set; }
}
B. Your JSON representation of the list is incorrect. It should be:
var e = [
{ "id": "foo", "perfVar": { "qid": "a", "tmr": "b"}},
{ "id": "foo", "perfVar": { "qid": "a", "tmr": "b"}}
];
C. You have to stringify the array and specify type: 'POST' to pass it to your MVC controller via ajax:
$.ajax({
url: '/run/submit',
data: JSON.stringify(e),
contentType: 'application/json, charset=utf-8',
dataType: 'json',
type: 'POST',
success: function (data) { alert(data); }
});
You can't directly map a key/value pair to a flat sequence. MVC has no idea how to do that.
You either need a custom model binder, or a better/easier option would be to change how you create the JSON on the client-side, so it actually matches up to your model.
Something like this:
var perfObjs =
{
{ id: 1, perfVar: { qId: 1, tmr: 0 }},
{ id: 2, perfVar: { qId: 2, tmr: 0 }},
}
$.post("/run/submit", perfObjs, function(data) { alert(data);}, "application/json");
Because the controller does not recognize the json value as List.
Why not just pass the raw string to your controller and let your controller convert the json string to object? that will be much more easier.