I've written a csharp app which queries our load balancers (which are setup in an active/passive configuration) to determine which is the active. The load balancers have a REST API which I'm querying as such:
public void GetActiveLB()
{
// Create a new RestClient and RestRequest
var client = new RestClient("https://myloadbalancer.domain.local");
var request = new RestRequest("mgmt/tm/cm/failover-status", Method.GET);
// Specify authentication
client.Authenticator = new HttpBasicAuthenticator("myusername", "supersecret");
// ask for the response to be in JSON syntax
request.RequestFormat = DataFormat.Json;
//send the request to the web service and store the response when it comes back
var queryResult = client.Execute(request);
// Create a new Deserializer to be able to parse the JSON object
RestSharp.Deserializers.JsonDeserializer deserial = new JsonDeserializer();
var JSONObj = deserial.Deserialize<Dictionary<string, string>>(queryResult);
string lbstatus = JSONObj["description"];
}
The JSON returned to me looks like this:
{
"kind":"tm:cm:failover-status:failover-statusstats",
"selfLink":"https://localhost/mgmt/tm/cm/failover-status?ver=11.6.0",
"entries": {
"https://localhost/mgmt/tm/cm/failover-status/0": {
"nestedStats": {
"entries": {
"color": {
"description": "green"
},
"https://localhost/mgmt/tm/cm/failoverStatus/0/details": {
"nestedStats": {
"entries": {
"https://localhost/mgmt/tm/cm/failoverStatus/0/details/0": {
"nestedStats": {
"entries": {
"details": {
"description": "active for /Common/traffic-group-1"
}
}
}
}
}
}
},
"status": {
"description": "ACTIVE"
},
"summary": {
"description": "1/1 active"
}
}
}
}
}}
Here's a prettier formatted version:)
The path to the item I want is:
[JSON].entries.https://localhost/mgmt/tm/cm/failover-status/0.nestedStats.entries.status.description
What I am struggling with is how to get the value of this item particularly because it seems to be nested multiple times. Is there a way to provide an absolute path?
Thank You
Brad
If the json is always structured the same way you can create some poco's that nest themselves and then deserialise with the json deserialisation:
eg:
[DataContract]
public class JsonResponse
{
[datamember]
public string kind;
[datamember]
public string selflink;
[datamember]
public Entry entries; //we nest another object here just as in the json
}
[DataContract]
public class Entry
{
[datamember]
public nestedstat nestedstats;
}
(this is just loosly typed)
then:
JsonResponse response = new JavaScriptSerializer().Deserialize<JsonResponse>(jsonasstring);
The easiest way to do it is to use the dynamic keyword like this:
dynamic JSONObj =
deserial
.Deserialize<Dictionary<string, object>>(queryResult); //Notice how I am using Dictionary<string, object> instead of Dictionary<string, string> since some of the values are actually parents of other values so they will be presented as dictionaries themselves.
var lbstatus =
JSONObj
["entries"]
["https://localhost/mgmt/tm/cm/failover-status/0"]
["nestedStats"]
["entries"]
["status"]
["description"];
If you don't use the dynamic keyword then you would have to cast JSONObj["entries"] into a Dictionary<string,object>, and then when you access ["https://localhost/mgmt/tm/cm/failover-status/0"] on that dictionary, you would need to cast the result again into Dictionary<string,object> ... etc.
In this case, the dynamic keyword will make it very much easier.
If you want to get the result from an absolute path, you can do something like this with dynamic:
dynamic JSONObj = deserial.Deserialize<Dictionary<string, object>>(queryResult);
string path =
"entries.https://localhost/mgmt/tm/cm/failover-status/0.nestedStats.entries.status.description";
dynamic value = JSONObj;
foreach (var sub_path in path.Split('.'))
{
value = value[sub_path];
}
var lbstatus = value.ToString();
Related
I have a below Jason format in which the Claims will be a array collection now I need to read all the Claims(which is a collection in below json) related to the policyid from c# , could anyone help me resoling it
{
"ClaimList": [{
"Claims": ["CL8901"],
"PolicyID": "W1234sd",
"ClaimsCount": 1
}, {
"Claims": ["CL3456", "CL1234"],
"PolicyID": "T1234sd",
"ClaimsCount": 2
}, {
"Claims": ["CL1321"],
"PolicyID": "C1234sd",
"ClaimsCount": 1
}]
}
string json = Util.ReadLine<string>();
JObject.Parse(json).SelectToken("ClaimList").Select(cl => new
{
PolicyId = cl.SelectToken("PolicyID"),
Claims = cl.SelectToken("Claims").ToObject<List<string>>()
}).Dump();
Linqpad code
http://share.linqpad.net/vqoav5.linq
To achieve what you need, do the following:
Follow my answer here to create C# classes for your json
Use NewtonSoft NuGet library to deserialize the JSON to C# objects
Perform whatever processing you need on the deserialized items
Here is some code once you have done the above:
var claims = JsonConvert.DeserializeObject<Rootobject>("YourJsonHere");
IEnumerable<Claimlist> claimsForPolicy=
claims.ClaimList.Where(x => x.PolicyID == "whateverYouNeed");
If you can use the Json.NET library (NuGet), this is pretty straightforward. First make sure you have a Claim class that has the structure of those inner objects in your JSON:
class Claim
{
public List<string> Claims { get; set; }
public string PolicyID { get; set; }
public int ClaimsCount { get; set; }
}
Having that class available, you can use Json.NET to do something like this:
using Newtonsoft.Json;
// ...
string yourJson = getYourJsonStringSomehow();
var claimsDict =
JsonConvert.DeserializeObject<Dictionary<string, List<Claim>>>(yourJson);
That will produce a Dictionary with one key: "ClaimsList", and the value will be a List of your Claim objects:
var claimsList = claimsDict["ClaimsList"];
var firstClaim = claimsList[0];
Console.WriteLine(firstClaim.PolicyID);
// Should print W1234sd
You can try this, first lets create a Json class for your json data:
public class JsonDoc
{
//I am adding an index on constructor for looping purposes
public JsonDoc(string json, int index)
{
JObject jObject = JObject.Parse(json);
JToken jResult = jObject["ClaimList"];
Claims = jResult[index]["Claims"].ToObject<string[]>();
}
//This constructor will return the number of count under ClaimList node
public JsonDoc(string json)
{
JObject jObject = JObject.Parse(json);
JToken jResult = jObject["ClaimList"][0];
intCount = jResult.Count();
}
private string[] Claims { get; set; }
public int intCount { get; set; }
}
Then to use this class for your Json data, first add a reference of Newtonsoft Json.
using Newtonsoft.Json.Linq;
Then on your sample data, I read all the data via file using StreamReader, loop on it and put all the data under a List:
private static void Main(string[] args)
{
using (StreamReader sr = new StreamReader(#"C:\Folder\myjson.json"))
{
string json = sr.ReadToEnd();
JsonDoc jSon = new JsonDoc(json);
//This will get the length of the array under ClaimList node
int intCount = jSon.intCount;
List<JsonDoc> lstResult = new List<JsonDoc>();
for (int x = 0; x < intCount; x++)
{
lstResult.Add(new JsonDoc(json, x));
}
}
}
The result is a List of JsonDoc class with array of string as part of property. This array of string is the result on your Claims Node. This JsonDoc class contains property Claims which is a string array which contains your Claims node:
I am receiving a JSON string from API that is structured in not a good way to be handled in the App.
I chose to create a custom serialiser for this JSON data (rather then having two different classes for data received and used in app).
Following a lot of tutorials I managed to put together a custom serialiser for a single object. However, I need to work with lists of these objects (there will be more different data that will come in these weird lists, that needs custom handling).
Is there a built in way I can set my custom serialiser to work with each object in the list? Or do I need to split the JSON object manually, and feed chunks of it to custom serialiser?
Any other suggestions how to handle this situation is appreciated.
User class:
[JsonConverter(typeof(UserSerializer))]
public class User
{
public int id;
public string displayName;
public string email;
public int total_points;
public float total_values;
}
The deserialiser:
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
JObject jObjectRoot = JObject.Load(reader);
var root = jObjectRoot.Properties().ToList();
JObject jObjectData = JObject.Load(root[2].Value.CreateReader());
var data = jObjectData.Properties().ToList();
return new User {
id = (int)root[1].Value,
displayName = (string)data[0].Value,
email = (string)data[1].Value,
total_points = (int)data[2].Value,
total_values = (float)data[3].Value
};
}
UPDATE:
Also the code that parses the json string to single user object:
public static void ProcessJSON(string json)
{
User user = JsonConvert.DeserializeObject<User>(json);
}
And the JSON itself:
[
{
"type": "users",
"id": 1,
"attr": {
"display_name": "user2",
"email": "user2#email.com",
"total_points": 4,
"total_values": 32.34
},
"relationships": {
"points_received": {
"links": {
"self": "tipjar/users/1/relationships/points",
"related": "tipjar/users/1/points"
}
},
"points_given": {
"links": {
"self": "tipjar/users/1/relationships/awarded",
"related": "tipjar/users/1/awarded"
}
}
}
}
]
Thanks
You can get the list of user objects without a custom converter like this:
var userList = JArray.Parse(json)
.Select(t => new User()
{
id = int.Parse(t["id"].ToString()),
displayName = t["attr"]["display_name"].ToString(),
email = t["attr"]["email"].ToString(),
total_points = int.Parse(t["attr"]["total_points"].ToString()),
total_values = float.Parse(t["attr"]["total_values"].ToString()),
}).ToList();
public static void ProcessJSON(string json)
{
User u = new User();
var test = JsonConvert.DeserializeObject(json);
if (test.GetType() == typeof(User))
u = (User)test;
}
Not 100% on how the serialize works, but this seemed to have worked on the test app I made.
It might be a bit silly. But you could test on the different types of objects returned...
I am trying to extract the Picture url from the Json response from Facebook Api.
I get this result.Text
{"name":"John Wheeler",
"id":"1374317669554451",
"picture":{
"data":{
"is_silhouette":false,
"url":"https:\/\/fbcdn-profile-a.akamaihd.net\/hprofile-ak-xpf1\/v\/t1.0-1\/p50x50\/10930189_1374295206223364_7603927373095864161_n.jpg?oh=1f1a16fdd68dd9aa4ccc141d8ad38ed4&oe=55B344AC&__gda__=1437883587_e8970bb6ff145728e14118a180e5b40a"}}}
and this is the code to try to extract the info
//Deserializing JSON returned from server
Dictionary<string, object> JSON = Json.Deserialize(result.Text) as Dictionary<string, object>;
List<object> data = JSON["data"] as List<object>;
//Loop to traverse and process all the items returned from the server.
for (int i = 0; i < data.Count; i++)
{
string id = System.Convert.ToString(((Dictionary<string, object>)data[i])["id"]);
string name = System.Convert.ToString(((Dictionary<string, object>)data[i])["name"]);
Dictionary<string, object> picInfo = ((Dictionary<string, object>)data[i])["picture"] as Dictionary<string, object>;
string url = Util.DeserializePictureURLObject(picInfo);
}
I get an error KeyNotFoundException: The given key was not present in the dictionary.
John
Your code doesn't match the JSON shown. Your code assumes that there is a top-level property "data" that refers to an array, however this is not the case. Your JSON contains no arrays, merely a chain of properties picture -> data -> url, like so:
{
"name":"John Wheeler",
"id":"1374317669554451",
"picture":{
"data":{
"is_silhouette":false,
"url":"https:\/\/fbcdn-profile-a.akamaihd.net\/hprofile-ak-xpf1\/v\/t1.0-1\/p50x50\/10930189_1374295206223364_7603927373095864161_n.jpg?oh=1f1a16fdd68dd9aa4ccc141d8ad38ed4&oe=55B344AC&__gda__=1437883587_e8970bb6ff145728e14118a180e5b40a"
}
}
}
Thus, to extract this information, you must do:
var url = obj.ToDict()["picture"].DeserializePictureURLObject();
var name = System.Convert.ToString(obj.ToDict()["name"]);
var id = System.Convert.ToString(obj.ToDict()["id"]);
Using the extension methods:
public static class Util
{
public static IDictionary<string, object> ToDict(this object jsonObject)
{
return (IDictionary<string, object>)jsonObject;
}
public static string DeserializePictureURLObject(this object pictureObj)
{
// Adapted from http://answers.unity3d.com/questions/921336/found-my-highscore-on-facebook.html?sort=oldest
var picture = pictureObj.ToDict()["data"].ToDict();
object urlH = null;
if (picture.TryGetValue("url", out urlH))
{
return (string)urlH;
}
return null;
}
}
Your parsing code would work for JSON that looks like this:
{
"data":[
{
"name":"John Wheeler",
"id":"1374317669554451",
"picture":{
"data":{
"is_silhouette":false,
"url":"https:\/\/fbcdn-profile-a.akamaihd.net\/hprofile-ak-xpf1\/v\/t1.0-1\/p50x50\/10930189_1374295206223364_7603927373095864161_n.jpg?oh=1f1a16fdd68dd9aa4ccc141d8ad38ed4&oe=55B344AC&__gda__=1437883587_e8970bb6ff145728e14118a180e5b40a"
}
}
}
]
}
I am working on building an app that accepts orgunitid and creates a new section associated with orgunitid. I'm using c#.
Here is my code.
string orgUnitId = textBoxOrgUnitId.Text;
string sectionCreateRoute = "/d2l/api/lp/1.0/" + orgUnitId + "/sections/";
var client = new RestClient(host);
var valenceAuthenticator = new D2L.Extensibility.AuthSdk.Restsharp.ValenceAuthenticator(userContext);
var requestCreateSection = new RestRequest(sectionCreateRoute, Method.POST);
valenceAuthenticator.Authenticate(client, requestCreateSection);
And, the JSON data I should provide will look like this.
{
"Name": "Test Section",
"Code": "" ,
"Description": { "Content": "Test", "Type" : "HTML" }
}
How can I create a new section with this JSON data.
Thanks,
Phillip
I've tried this code, but it still does not create a section.
string orgUnitId = textBoxOrgUnitId.Text;
string sectionCreateRoute = "/d2l/api/lp/1.0/" + orgUnitId + "/sections/";
var client = new RestClient(host);
var valenceAuthenticator = new D2L.Extensibility.AuthSdk.Restsharp.ValenceAuthenticator(userContext);
var requestCreateSection = new RestRequest(sectionCreateRoute, Method.POST);
requestCreateSection.AddJsonBody(new
{
Name = "Section Test",
Code = "156156",
Description = new { Content = "Test", Type = "Html" }
});
valenceAuthenticator.Authenticate(client, requestCreateSection);
Because you're using ResSharp I would recommend calling the following method;
public IRestRequest AddJsonBody(object obj)
{
this.RequestFormat = DataFormat.Json;
return this.AddBody(obj, "");
}
However in order to use this you need a C# object to represent that data. The class definitions would look something like this;
public class NewSectionPostBody
{
public string Name;
public string Code;
public SectionContentType Description;
}
public class SectionContentType
{
public string Content;
public string Type;
}
With these and your existing code I can do the following;
var requestCreateSection = new RestRequest(sectionCreateRoute, Method.POST);
// use object initializer to make instance for body inline
requestCreateSection.AddJsonBody(new NewSectionPostBody{
Name="Test Section",
Code=String.Empty,
Description= new SectionContentType { Content="Test", Type="HTLM" }
});
valenceAuthenticator.Authenticate(client, requestCreateSection);
RestSharp handles the object to json string serialization so you can basically just pass any object into that method and the resulting json will be used as the post body.
One last thing; if this is a one off request you don't even need to define the types I used for the body. You can just use the same inline initilization constructs to make an anonymous type if you were to just remove the classnames ie;
requestCreateSection.AddJsonBody(new {
Name="Test Section",
Code=String.Empty,
Description= new { Content="Test", Type="HTLM" }
});
^^ Rather than instantiating user defined class types I use anonymous types. If you're not able to reuse the types which make up the post body, this is a more efficient way of setting up the request.
I use the DataContractJsonSerializer to parse a json string into a object hierarchie.
The json string looks like this:
{
"groups": [
{
"attributes": [
{
"sortOrder": "1",
"value": "A"
},
{
"sortOrder": "2",
"value": "B"
}
]
},
{
"attributes": {
"sortOrder": "1",
"value": "C"
}
}
]
}
As you can see the sub value of "attributes" can be an array or a single item.
I found the code part where the problem occures:
[DataContract]
public class ItemGroup
{
[DataMember(Name="attributes")]
public List<DetailItem> Items { get; set; }
}
This works for the first one but fails on the second one.
Has anyone an answer for this?
Thx
If you control how the JSON is created then make sure that attributes is an array even if it only contains one element. Then the second element will look like this and parse fine.
{
"attributes": [{
"sortOrder": "1",
"value": "C"
}]
}
As Daniel said, if you can control the creation of Json, it is better to continue that way.
But if you can't, then you can use Json.Net library & the JsonObject class from
this link to write some code like:
JObject o = (JObject)JsonConvert.DeserializeObject(input);
dynamic json = new JsonObject(o);
foreach (var x in json.groups)
{
var attrs = x.attributes;
if (attrs is JArray)
{
foreach (var y in attrs)
{
Console.WriteLine(y.value);
}
}
else
{
Console.WriteLine(attrs.value);
}
}
I tried to get this working with DataContractJsonSerializer, JavaScriptSerializer, and JSON.Net and none would deserialize directly to an object successfully in all cases. I used a similar approach as L.B, using JSON.Net, although without the use of dynamics and the extra JsonObject class. Adapting my code to your scenario would look something like the following:
private List<ItemGroup> ParseItemGroupList(string input)
{
JObject json = JObject.Parse(input);
List<ItemGroup> groups = new List<ItemGroup>();
JArray gArray = json["groups"] as JArray;
foreach (var gToken in gArray)
{
ItemGroup newGroup = new ItemGroup();
JToken attrToken = gToken["attributes"] as JToken;
if (attrToken is JArray)
{
newGroup.Items = attrToken.Children().Select(MapDetailItem()).ToList();
}
else
{
newGroup.Items = new List<DetailItem>() { MapDetailItem().Invoke(attrToken) };
}
groups.Add(newGroup);
}
return groups;
}
private static Func<JToken, DetailItem> MapDetailItem()
{
return json => new DetailItem
{
SortOrder = (string)json["sortOrder"],
Value = (string)json["value"]
};
}
Hopefully, someone will add a setting for JSON.Net to allow it to force deserialization to a collection with a single item rather than throwing an exception. It's a shame that you have to do all of the parsing manually when there is only one small portion of the JSON that doesn't parse correctly automatically.