C# parsing multiple json - c#
The JSON data is as follows:
{"Sucess":true,
"Code":0,
"Msg":"Sucess",
"Data":{
"UserDayRanking":
{
"UserID":11452112,
"UserCharm":0,
"UserName":"gay",
"UserGender":1,
"UserLevel":36,
"UserPhoto":"http://res.xxx.com/2020/3/16/63719926625601201487545U11452112.jpeg",
"Ranking":0,
"IsNobility":0,
"NobilityType":0,
"NobilityLevel":0,
"UserShowStyle":null,
"LiveLevelUrl":null,
"IsStealth":false},
"DayRankingList":[
{
"UserID":3974854,
"UserCharm":114858,
"UserName":"jack",
"UserGender":1,
"UserLevel":91,
"UserPhoto":"http://res.xxx.com/2020/2/15/63717400601924412312384U3974854.jpeg",
"Ranking":2,
"IsNobility":1,
"NobilityType":1,
"NobilityLevel":3,
"UserShowStyle":
{
"NameColor":100102,
"BorderColor":100403,
"LiangMedal":0,
"DztCountDown":0,
"Mounts":100204,
"LiveLevelCode":0,
"LiveRights":null
},
"LiveLevelUrl":null,
"IsStealth":false
},
{"UserID":6231512,
"UserCharm":22644,
"UserName":"red.girl",
"UserGender":1,
"UserLevel":57,
"UserPhoto":"http://res.xxx.com/2019/11/20/63709843050801519858823U6231512.jpeg",
"Ranking":3,
"IsNobility":0,
"NobilityType":0,
"NobilityLevel":0,
"UserShowStyle":{
"NameColor":0,
"BorderColor":0,
"LiangMedal":0,
"DztCountDown":0,
"Mounts":0,
"LiveLevelCode":0,
"LiveRights":null
},
"LiveLevelUrl":null,
"IsStealth":false}
],
"LiveCharmSwitch":1,
"IsSelf":false
}
}
I want to use c # extraction
"UserID": 3974854,
"UserCharm": 114858,
"UserName": "jack",
"UserID":6231512,
"UserCharm":22644,
"UserName":"red.girl",
That is to extract UserID, UserCharm, UserName,This json has many layers,
What I want after the extraction is,id is sorted in order
id = 1, UserID = 3974854, UserCharm = 114858, UserName = jack
id = 2, UserID = 6231512, UserCharm = 22644, UserName = red.girl
I use the following code, but only extract the first one
string json = #"{"Sucess":true,"Code":0,"Msg":"Sucess","Data":{"UserDayRanking":{"UserID":11452112,"UserCharm":0,"UserName":"gay","UserGender":1,"UserLevel":36,"UserPhoto":"http://res.xxx.com/2020/3/16/63719926625601201487545U11452112.jpeg","Ranking":0,"IsNobility":0,"NobilityType":0,"NobilityLevel":0,"UserShowStyle":null,"LiveLevelUrl":null,"IsStealth":false},"DayRankingList":[{"UserID":3974854,"UserCharm":114858,"UserName":"jack","UserGender":1,"UserLevel":91,"UserPhoto":"http://res.xxx.com/2020/2/15/63717400601924412312384U3974854.jpeg","Ranking":2,"IsNobility":1,"NobilityType":1,"NobilityLevel":3,"UserShowStyle":{"NameColor":100102,"BorderColor":100403,"LiangMedal":0,"DztCountDown":0,"Mounts":100204,"LiveLevelCode":0,"LiveRights":null},"LiveLevelUrl":null,"IsStealth":false},{"UserID":6231512,"UserCharm":22644,"UserName":"red.girl","UserGender":1,"UserLevel":57,"UserPhoto":"http://res.xxx.com/2019/11/20/63709843050801519858823U6231512.jpeg","Ranking":3,"IsNobility":0,"NobilityType":0,"NobilityLevel":0,"UserShowStyle":{"NameColor":0,"BorderColor":0,"LiangMedal":0,"DztCountDown":0,"Mounts":0,"LiveLevelCode":0,"LiveRights":null},"LiveLevelUrl":null,"IsStealth":false}],"LiveCharmSwitch":1,"IsSelf":false}}";
List<Info> jobInfoList = JsonConvert.DeserializeObject<List<Info>>(z);
foreach (Info jobInfo in jobInfoList)
{
//Console.WriteLine("UserName:" + jobInfo.UserName);
}
public class Info
{
public string UserCharm { get; set; }
public string UserName { get; set; }
public data DayRankingList { get; set; }
}
public class data
{
public int UserID { get; set; }
public string UserCharm { get; set; }
public string UserName { get; set; }
public string UserGender { get; set; }
public string UserLevel { get; set; }
}
The above code only shows username = jack,Never show username = red.girl
As it looks to me then you want some details from your JSON has the which is in DayRankingList. As you only want some data then we can use a tool like http://json2csharp.com/ to create our classes and then remove what we don't need. Then we end up with the following classes.
public class DayRankingList
{
public int UserID { get; set; }
public int UserCharm { get; set; }
public string UserName { get; set; }
}
public class Data
{
public List<DayRankingList> DayRankingList { get; set; }
}
public class RootObject
{
public Data Data { get; set; }
}
Which you can deserialise like this
string json = .....
var root = JsonConvert.DeserializeObject<RootObject>(json);
Then if you wish, you can extract the inner data into a new List<> and then just work on that.
List<DayRankingList> rankingLists = root.Data.DayRankingList;
//Do something with this, such as output it
foreach(DayRankingList drl in rankingLists)
{
Console.WriteLine(String.Format("UserId {0} UserCharm {1} UserName {2}",drl.UserId, drl.UserCharm, drl.UserName));
}
You can use Json.Linq to parse your JSON into JObject and enumerate DayRankingList items (since it's an array). Then convert every item into data class and order the result sequence by UserID
var jObject = JObject.Parse(json);
var rankingList = (jObject["Data"] as JObject)?.Property("DayRankingList");
var list = rankingList.Value
.Select(rank => rank.ToObject<data>())
.OrderBy(item => item?.UserID);
foreach (var user in list)
Console.WriteLine($"{user.UserID} {user.UserName}");
Another way is copy your JSON, go to Edit->Paste Special->Paste JSON as classes menu in Visual Studio and generate a proper class hierarchy (I've got 5 classes, they are quite long to post here), then use them during deserialization
The most type-safe way is to define the class structure that you want, like jason.kaisersmith suggested.
To have the final format you need, though, you might want to do an extra Linq Order and Select, to include the id:
var finalList = rankingLists.OrderBy(rl => rl.UserId).Select((value, index) => new
{
id = index,
value.UserId,
value.UserCharm,
value.UserName
});
foreach (var drl in finalList)
{
Console.WriteLine($"Id = {drl.id}, UserId = {drl.UserId}, UserCharm = {drl.UserCharm}, UserName = {drl.UserName}");
}
Related
how to pull out array of string values from a deserialized JSON response
I am pretty new to coding and here is my requirement: I am getting a JSON response which has an array of values (refer read,update,delete in the below JSON response) The number of values is dynamic and tend to vary each time. I want to know how to retrieve them and put into an string array and return the values Eg.: end result should be like string[] deleteValues = {"MCS:Menu:Admin","MCS:test"} In case if there is answer already available to this question, please point me in the right direction. Thanks in advance ========================================== I am able to get the values this way... string value1 = new JavaScriptSerializer().Deserialize<JSON_Deconstructor>(resp).Permitted[0].Delete[0].ToString(); string value2 = new JavaScriptSerializer().Deserialize<JSON_Deconstructor>(resp).Permitted[0].Delete[1].ToString(); but since the number of values in delete is dynamic, i need to how to pull them. ==================== the code snippet: string resp = new StreamReader(request1.GetResponse().GetResponseStream()).ReadToEnd(); // resp is a JSON response from a server JSON_Deconstructor dc = new JSON_Deconstructor { }; dc.Permitted = new Permitted[1]; string value1 = new JavaScriptSerializer().Deserialize<JSON_Deconstructor>(resp).Permitted[0].Delete[0].ToString(); string value2 = new JavaScriptSerializer().Deserialize<JSON_Deconstructor>(resp).Permitted[0].Delete[1].ToString(); ================== JSON_Deconstructor class contents: public class JSON_Deconstructor { public Permitted[] Permitted { get; set; } public Denied[] Denied { get; set; } } ================== Permitted class contents: public class Permitted { public string[] Read { get; set; } public string[] Update { get; set; } public string[] Delete { get; set; } } ================= JSON response: { "Permitted": [ { "read": [ "MCS:Menu:Admin" ], "update": [ "MCS:test" ], "delete": [ "MCS:Menu:Admin", "MCS:test" ] } ] }
First add jsonProperty to your class in order to be able to serialize. public class Permitted { [JsonProperty("read")] public string[] Read { get; set; } [JsonProperty("update")] public string[] Update { get; set; } [JsonProperty("delete")] public string[] Delete { get; set; } } //Response contains a list of permitted objects in Permitted property public class PermittedResponse { public List<Permitted> Permitted { get; set; } } then in you method de serialize your response and loop through results to build your arrays. List<string> deletedValues = new List<string>(); List<string> readValues = new List<string>(); List<string> updateValues = new List<string>(); PermittedResponse response = JsonConvert.DeserializeObject<PermittedResponse>(serializedJson); response.Permitted.ForEach(e => { deletedValues = deletedValues.Concat(e.Delete).ToList(); readValues = readValues.Concat(e.Read).ToList(); updateValues = updateValues.Concat(e.Update ).ToList(); });
Use Newtonsoft.Json. You can get it from NuGet. This is very simple and powerful library for Json. Now, you should create a class, like: public class Item { public List<string> MCS { get; set; } = new List<string>(); } public class PermitedItem { public Item read {get; set;} public Item update {get; set;} public Item delete {get; set;} } public class MyResponse { public List<PermittedItem> Permitted = new List<PermittedItems>(); } And then you use it like that: MyResponse result = JsonConvert.DeserializeObject<MyResponse>(jsonAsString); This should work.
C# Json.Net - How to deserialize an array of objects containing an array of other objects
The Json data received from the http server is like this: [ { "token":"NlhYnzF0xqG" }, [ { "ts":"2019-03-21 14:06:22.123", "id":"CC_RTC_Second", "val":"22" }, { "ts":"2019-03-21 14:06:00.096", "id":"CC_RTC_Minute", "val":"6" }, { "ts":"2019-03-21 14:00:00.276", "id":"CC_RTC_Hour", "val":"14" } ] ] I have tried some techniques presented in Newtonsoft.Json documentation, but I could not find the correct way. I spent two days by testing the solutions from StackOverflow answers, but with no success. What C# types and techniques should I use in this particular case? Data structure can vary: complete list of attributes is: td, id, val, flags, type, uts, nr. All of them are strings. Server can omit the attrs if they do not exist, so for example I can obtain only ts + id. Is there any way how to work with such a data?
First of all your json is quite complicated and its tedious job to create a class hierarchy for your json, But one simple approach is that if you parse your JSON to JArray and then takes 0th element to one class And all remaining into list of another class Then might be you can retrieve all your json data string json = File.ReadAllText(#"Path to your json"); JArray jArray = JArray.Parse(json); Token token = jArray[0].ToObject<Token>(); jArray.RemoveAt(0); RandomData[] tokenData = jArray.First.ToObject<RandomData[]>(); //--------------------Print Data to Console------------------- Console.WriteLine(token.token + "\n"); foreach (var item in tokenData) { Console.WriteLine("ts: " + item.ts); Console.WriteLine("id: " + item.id); Console.WriteLine("val: " + item.val + "\n"); } Console.ReadLine(); And classes are, class Token { public string token { get; set; } } class RandomData { public string ts { get; set; } public string td { get; set; } public string id { get; set; } public string val { get; set; } public string flags { get; set; } public string type { get; set; } public string uts { get; set; } public string nr { get; set; } } Output: Note: You need to install NewtonSoft NuGet package and import using Newtonsoft.Json.Linq; namespace to your program.
There is my version of answer: var strData = #"[{ 'token': 'NlhYnzF0xqG' }, [{ 'ts': '2019-03-21 14:06:22.123', 'id': 'CC_RTC_Second', 'val': '22' }, { 'ts': '2019-03-21 14:06:00.096', 'id': 'CC_RTC_Minute', }, { 'id': 'CC_RTC_Hour', 'val': '14' }] ]"; var result = JsonConvert.DeserializeObject<List<JToken>>(strData); var tokens = result.Where( x=> x.Type == JTokenType.Object).Select(x=> x.ToObject<Token>()); var innerData = result.Where(x => x.Type == JTokenType.Array).Select(x => x.ToObject<List<InnerData>>()); there are classes: public class Token { public string token { set; get; } } public class InnerData { public string ts { set; get; } public string id { set; get; } public string val { set; get; } } You could print results as was mention before : foreach (var token in tokens) { Console.WriteLine("ts: " + token.token); }
NEST Api SearchAfter return null in NEST but works in Kibana
We are using elastic search just for document search in our application so we don't have any one expert in it. I was able to use TermQuery, SimpleQueryStringQuery and MatchPhraseQuery successfully. But I found out in documentation that using From & Size for pagination is not good for production and Search After is recommended. But my implementation return null. It is confusing for me what should be in <Project> parameter as shown in Nest API Object Initializer Syntax in docs here. My code looks like this: var request = new SearchRequest<ElasticSearchJsonObject._Source> { //Sort = new List<ISort> //{ // new SortField { Field = Field<ElasticSearchJsonObject>(p=>)} //}, SearchAfter = new List<object> { }, Size = 20, Query = query }; Reality is I don't understand this. Over here ElasticSearchJsonObject._Source is the class to map returned results. My documents are simple text documents and I only want documents sorted according to score so document Id is not relevant. There was already a question like this on SO but I can't find it somehow. Update After looking at answer I updated my code and though query obtained does work. It return result in kibana but not in NEST. This is the new updated code: var request = new SearchRequest<ElasticSearchJsonObject.Rootobject> { Sort = new List<ISort> { new SortField { Field = "_id", Order = SortOrder.Descending} }, SearchAfter = new List<object> { "0fc3ccb625f5d95b973ce1462b9f7" }, Size = 1, Query = query }; Over here I am using size=1 just for test as well as hard code _id value in SearchAfter. The query generated by NEST is: { "size": 1, "sort": [ { "_id": { "order": "desc" } } ], "search_after": [ "0fc3ccb625f5d95b973ce1462b9f7" ], "query": { "match": { "content": { "query": "lahore", "fuzziness": "AUTO", "prefix_length": 3, "max_expansions": 10 } } } } The response from the ES does say successful but no results are returned. Results do return in Kibana Query status is successful But... Total returned is 0 in NEST Sort value is null in kibana I used TrackScores = true to solve this issue Here is the debug information: Valid NEST response built from a successful low level call on POST: /extract/_source/_search?typed_keys=true # Audit trail of this API call: - [1] HealthyResponse: Node: http://localhost:9200/ Took: 00:00:00.1002662 # Request: {"size":1,"sort":[{"_id":{"order":"desc"}}],"search_after":["0fc3ccb625f5d95b973ce1462b9f7"],"query":{"match":{"content":{"query":"lahore","fuzziness":"AUTO","prefix_length":3,"max_expansions":10}}}} # Response: {"took":3,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}} So please tell me where I am wrong and what can be the problem and how to solve it. Update 2: Code in Controller: Connection String: var node = new Uri("http://localhost:9200"); var settings = new ConnectionSettings(node); settings.DisableDirectStreaming(); settings.DefaultIndex("extract"); var client = new ElasticClient(settings); Query: var query = (dynamic)null; query = new MatchQuery { Field = "content", Query = content, Fuzziness = Fuzziness.Auto, PrefixLength = 3, MaxExpansions = 10 }; Query Builder var request = new SearchRequest<ElasticSearchJsonObject.Rootobject> { Sort = new List<ISort> { new SortField { Field = "_id", Order = SortOrder.Descending} }, SearchAfter = new List<object> { documentid //sent as parameter }, Size = 1, //for testing 1 other wise 10 TrackScores = true, Query = query }; JSON Query I use this code to get query I posted above. This query is then passed to kibana with GET <my index name>/_Search and there it works var stream = new System.IO.MemoryStream(); client.SourceSerializer.Serialize(request, stream); var jsonQuery = System.Text.Encoding.UTF8.GetString(stream.ToArray()); ES Response string responseJson = ""; ElasticSearchJsonObject.Rootobject response = new ElasticSearchJsonObject.Rootobject(); var res = client.Search<object>(request); if (res.ApiCall.ResponseBodyInBytes != null) { responseJson = System.Text.Encoding.UTF8.GetString(res.ApiCall.ResponseBodyInBytes); try { response = JsonConvert.DeserializeObject<ElasticSearchJsonObject.Rootobject>(responseJson); } catch (Exception) { var model1 = new LoginSignUpViewModel(); return PartialView("_NoResultPage", model1); } } This is where things go wrong. Above debug information was captured from response ElasticSearchJsonObject Some how I think problem might be here somewhere? The class is generated by taking response from NEST in Search request. using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace ESAPI { public class ElasticSearchJsonObject { public class Rootobject { public int took { get; set; } public bool timed_out { get; set; } public _Shards _shards { get; set; } public Hits hits { get; set; } } public class _Shards { public int total { get; set; } public int successful { get; set; } public int skipped { get; set; } public int failed { get; set; } } public class Hits { public int total { get; set; } public float max_score { get; set; } public Hit[] hits { get; set; } } public class Hit { public string _index { get; set; } public string _type { get; set; } public string _id { get; set; } public float _score { get; set; } public _Source _source { get; set; } } public class _Source { public string content { get; set; } public Meta meta { get; set; } public File file { get; set; } public Path path { get; set; } } public class Meta { public string title { get; set; } public Raw raw { get; set; } } public class Raw { public string XParsedBy { get; set; } public string Originator { get; set; } public string dctitle { get; set; } public string ContentEncoding { get; set; } public string ContentTypeHint { get; set; } public string resourceName { get; set; } public string ProgId { get; set; } public string title { get; set; } public string ContentType { get; set; } public string Generator { get; set; } } public class File { public string extension { get; set; } public string content_type { get; set; } public DateTime last_modified { get; set; } public DateTime indexing_date { get; set; } public int filesize { get; set; } public string filename { get; set; } public string url { get; set; } } public class Path { public string root { get; set; } public string _virtual { get; set; } public string real { get; set; } } } } I am sure this can be used to get response. Please note that in case of simple search this code works: so for this query below my code is working: var request = new SearchRequest { From = 0, Size = 20, Query = query };
Using from/size is not recommended for deep pagination because of the amount of documents that need to be fetched from all shards for a deep page, only to be discarded when finally returning an overall ordered result set. This operation is inherent to the distributed nature of Elasticsearch, and is common to many distributed systems in relation to deep pagination. With search_after, you can paginate forward through documents in a stateless fashion and it requires the documents returned from the first search response are sorted (documents are sorted by _score by default) passing the values for the sort fields of the last document in the hits from one search request as the values for "search_after": [] for the next request. In the Search After Usage documentation, a search request is made with sort on NumberOfCommits descending, then by Name descending. The values to use for each of these sort fields are passed in SearchAfter(...) and are the values of Project.First.NumberOfCommits and Project.First.Name properties, respectively. This tells Elasticsearch to return documents that have values for the sort fields that correspond to the sort constraints for each field, and relate to the values supplied in the request. For example, sort descending on NumberOfCommits with a supplied value of 775 means that Elasticsearch should only consider documents with a value less than 775 (and to do this for all sort fields and supplied values). If you ever need to dig further into any NEST documentation, click the "EDIT" link on the page: which will take you to the github repository of the documentation, with the original asciidoc markdown for the page: Within that page will be a link back to the original NEST source code from which the asciidoc was generated. In this case, the original file is SearchAfterUsageTests.cs in the 6.x branch
How to convert HttpResponseMessage having OData to a C# object?
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
JavaScriptDeseializer : Can not serialize array
My application is asp.net. I have to send some values back to server. For this I create a object serialize it and send it to server. At server I try to de-serialize it Following is my code [Serializable] public class PassData { public PassData() { } public List<testWh> SelectedId { get; set; } public string SelectedControlClientId { get; set; } public string GroupTypeId { get; set; } public string SectionTypeId { get; set; } } [Serializable] public class testWh { public testWh() { } public string Id { get; set; } } JavaScriptSerializer serializer = new JavaScriptSerializer(); //this can not serialize the SelectedId and the count remains 0 PassData data = serializer.Deserialize<PassData>(jsonString); //this serialize in an anonymous object with key value pair var data2 = serializer.DeserializeObject(textHiddenArguments.Text); Following is my Json Serialized String { "SelectedId":{"0":"ABCD","1":"JKLM"}, "SelectedControlClientId":"YTUTOOO", "GroupTypeId":3, "SectionTypeId":"1" } quotes escaped string "{\"SelectedId\":{\"0\":\"ABCD\",\"1\":\"JKLM\"},\"SelectedControlClientId\":\"YTUTOOO\",\"GroupTypeId\":3,\"SectionTypeId\":\"1\"}" My Problem is Selected Id is array of testWH object. But when I try to desrialize it, the SelectedId property of PassData which is list does not get serialized and count remains zero. I tried using array instead of List, which gave an exception "no parameter less constructor..." Could any one explain the what I am doing wrong here ?
The key problem here is that the JSON doesn't match the objects you have constructed. You can see this by writing the data you want and serializing: var obj = new PassData { SelectedId = new List<testWh> { new testWh { Id = "ABCD"}, new testWh { Id = "JKLM"} }, GroupTypeId = "3", SectionTypeId = "1", SelectedControlClientId = "YTUTOOO" }; string jsonString = serializer.Serialize(obj); which gives JSON like: {"SelectedId":[{"Id":"ABCD"},{"Id":"JKLM"}], "SelectedControlClientId":"YTUTOOO","GroupTypeId":"3","SectionTypeId":"1"} So now you need to decide which you want to change; the JSON or the classes. The following alternative class works fine with your original JSON, for example: public class PassData { public Dictionary<string,string> SelectedId { get; set; } public string SelectedControlClientId { get; set; } public string GroupTypeId { get; set; } public string SectionTypeId { get; set; } }