Get value from IEnumerable foreach loop - c#

I need to create a c# object from a JSON file, and have to following working solution:
JSON:
{
"AK": {
"Anchorage": [{
"Name": "John Doe",
"Address": "123 Main St.",
"City": "Anchorage",
"State": "AK",
"Zip": "12345"
}],
"Fairbanks": [{
"Name": "Sally Smith",
"Address": "987 Main St.",
"City": "Fairbanks",
"State": "AK",
"Zip": "98765"
}]
}
}
Code:
public class Location
{
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
// ------------------------------------------------------------------
string json = File.ReadAllText(#"C:json.txt");
dynamic deserialisedJson = JsonConvert.DeserializeObject(json);
var locations = new List<Location>();
foreach (var root in deserialisedJson)
{
foreach (var state in root)
{
foreach (var city in state)
{
foreach (var location in city)
{
Location loc = new Location();
loc.Name = location.First["Name"];
loc.Address = location.First["Address"];
loc.City = location.First["City"];
loc.State = location.First["State"];
loc.Zip = location.First["Zip"];
locations.Add(loc);
}
}
}
}
But I need to incorporate the above into an SSIS package, which only allows .NET 3.5 and below. The line of code below requires .NET 4.0 and above:
dynamic deserialisedJson = JsonConvert.DeserializeObject(json);
I'm trying to workaround this limitation by using IEnumerable, but I'm not sure of the syntax of how to grab the values I need?
string json = File.ReadAllText(#"C:json.txt");
var deserialisedJson = (IEnumerable)JsonConvert.DeserializeObject(json);
var locations = new List<Location>();
foreach (var root in deserialisedJson)
{
foreach (var state in (IEnumerable)root)
{
foreach (var city in (IEnumerable)state)
{
foreach (var location in (IEnumerable)city)
{
Location loc = new Location();
loc.Name = //What goes here???
loc.Address = //What goes here???
loc.City = //What goes here???
loc.State = //What goes here???
loc.Zip = //What goes here???
locations.Add(loc);
}
}
}
}

This uses Linq to JSON to select all the Location objects you want:
var deserialisedJson = (IEnumerable)JsonConvert.DeserializeObject(json);
JObject jObj = JObject.Parse(json);
//Get all tokens that are under AK/(some descendant)/all items from collection
var result = jObj.SelectTokens("AK.*.[*]")
.Select(x => new Location
{
Name = x["Name"].Value<string>(),
Address = x["Address"].Value<string>(),
City = x["City"].Value<string>(),
State = x["State"].Value<string>(),
Zip = x["Zip"].Value<string>(),
}).ToList();
Tested and this works in a .Net 3.5 project with a Newtonsoft.Json package suitable for the .Net

Here is a quick solution:
var deserialized = JsonConvert.DeserializeObject<JObject>(json);
var locations = (
from state in deserialized.Properties().Select(v => v.Value).OfType<JObject>()
from city in state.Properties().Select(v => v.Value).OfType<JArray>()
from location in city
select new Location
{
Name = location.Value<string>("Name"),
Address = location.Value<string>("Address"),
City = location.Value<string>("City"),
State = location.Value<string>("State"),
Zip = location.Value<string>("Zip")
}).ToList();

You can use the clases to let newtonsoft resolve what you need
public class Location
{
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class AK
{
public Location[] Anchorage { get; set; }
public Location[] Fairbanks { get; set; }
}
var ak = JsonConvert.DeserializeObject<AK>(json);

Related

How to read json string in c#

I am trying to parse manually a string in json. This is how my json look like
{{
"dbViews": [
{
"viewID": 0,
"viewColumns": [
{
"dbTitle": "ColNmid",
"viewTitle": "string",
"activated": true,
"activatedLabel": "Afficher"
},
{
"dbTitle": "ColNmdelete",
"viewTitle": "string",
"activated": true,
"activatedLabel": "Afficher"
}
]
}
],
"AddViewName": "test"
}}
This is how i am trying to read it.
UserViewDto User = new UserViewDto();
dynamic obj = JObject.Parse(json);
User.id = obj.dbViews.viewID;
User.viewName = obj.AddViewName;
foreach (var item in obj.viewColumns)
{
if (obj.dbTitle == "ColNmid")
{
User.ColNmid = obj.viewTitle;
}
}
I can only read addViewName, i can't seem to access viewID or viewColumn.
Update:
after the comments I obviously miss the second array. Here my new code witch work
UserViewDto User = new UserViewDto();
dynamic obj = JObject.Parse(json);
User.viewName = obj.AddViewName;
foreach (var view in obj.dbViews)
{
User.id = view.viewID;
foreach (var item in view.viewColumns)
{
if (item.dbTitle == "ColNmid")
{
User.ColNmid = item.viewTitle;
}
}
}
Your json in question is invalid (extra { and } at start and end). It seems that you are using Newtonsoft's Json.NET library. Usual approach is to create model corresponding to your json structure and deserialize it:
public class Root
{
[JsonProperty("dbViews")]
public List<DbView> DbViews { get; set; }
[JsonProperty("AddViewName")]
public string AddViewName { get; set; }
}
public class DbView
{
[JsonProperty("viewID")]
public long ViewId { get; set; }
[JsonProperty("viewColumns")]
public List<ViewColumn> ViewColumns { get; set; }
}
public class ViewColumn
{
[JsonProperty("dbTitle")]
public string DbTitle { get; set; }
[JsonProperty("viewTitle")]
public string ViewTitle { get; set; }
[JsonProperty("activated")]
public bool Activated { get; set; }
[JsonProperty("activatedLabel")]
public string ActivatedLabel { get; set; }
}
var result = JsonConvert.DeserializeObject<Root>();
You don't need to include all properties in your class, you can include only needed ones.
If you don't want to create custom models and want to loop through the JObject properties in your case you can do it for example like that:
var jObj = JObject.Parse(json);
foreach(var view in jObj["dbViews"]) // dbViews is an array
{
Console.WriteLine(view["viewID"]);
foreach (var viewColumn in view["viewColumns"]) // viewColumns is an array
{
Console.WriteLine(viewColumn["dbTitle"]);
}
}

Adding JObject to JArray

Im trying to add a new class called "Company" to a Json Array called Companies. I'm doing this using C# and Json .net Ive tried many different things. I have them all pares out and in Jobjects ready to be molded together but I can't find a way to do so. Im trying to get it to find "Companies" then insert the new company object in there.
This is what im trying to do.
public void CreateNewCompany()
{
Company company = new Company
{
CompanyName = textBox1.Text,
IPO = Convert.ToDouble(textBox2.Text),
Category = CategorycomboBox1.SelectedItem.ToString(),
Description = textBox4.Text,
StartDate = Convert.ToInt32(textBox5.Text)
};
AddProductListItemsToFinishedJSON(company);
AddNewsArticlesListItemsToFinishedJSON(company);
JObject newCompany = JObject.FromObject(company);
string existingFileContents = File.ReadAllText(path);
string newFileContents = newCompany.ToString();
var existingFileContentsToJSON = JObject.Parse(existingFileContents);
var newFileContentsToJSON = JObject.Parse(newFileContents);
Debug.WriteLine(existingFileContents);
SaveJSONFile(company);
}
public void SaveJSONFile(Company localcompany)
{
if (File.Exists(Path.Combine(#"D:\", "comp.json")))
{
File.Delete(Path.Combine(#"D:\", "comp.json"));
}
string RawJSON = JsonConvert.SerializeObject(localcompany);
string FormattedJSON = JToken.Parse(RawJSON).ToString(Formatting.Indented);
//Console.WriteLine(FormattedJSON);
File.WriteAllText(#"D:\comp.json", FormattedJSON);
}
These are the classes
public class Company
{
public string CompanyName { get; set; }
public double IPO { get; set; }
public string Category { get; set; }
public string Description { get; set; }
public int StartDate { get; set; }
public List<Product> Products = new List<Product>();
public List<NewsArticle> CompanySpecificNewsArticles = new List<NewsArticle>();
public List<string> EavesDropperList = new List<string>();
}
public class Product
{
[JsonProperty("ProductName")]
public string ProductName { get; set; }
}
public class NewsArticle
{
[JsonProperty("Type")]
public string Type { get; set; }
[JsonProperty("Content")]
public string Content { get; set; }
}
This is what the Json Looks like and I want to add it to 'Companies'
{
"Companies":[
{
"CompanyName":"",
"IPO":25.0,
"Category":"Gaming",
"Description":"A video game company",
"StartDate":"1-1-2000",
"Products":[
{
"ProductName":""
},
{
"ProductName":""
}
],
"CompanySpecificNewsArticles":[
{
"Type":"Positive",
"Content":"This company has had a very good year!"
},
{
"Type":"Negative",
"Content":"This company has had a very bad year!"
},
{
"Type":"Neutral",
"Content":"This company is doing okay, I guess"
}
],
"CompanySpecificEavesdropper":[
{
"Type":"Positive",
"Content":"This company has had a very good year!"
},
{
"Type":"Negative",
"Content":"This company has had a very bad year!"
},
{
"Type":"Neutral",
"Content":"This company is doing okay, I guess!"
}
]
}
//,
// Other companies omitted
]
}
A JSON file is just a text file, so there's no straightforward way to insert a record into the middle of the file. Instead, you will need to load the entire file into some in-memory representation, add your Company to the "Companies" array, then re-serialize the file back to disk.
To accomplish this, first create the following extension methods:
public class JsonExtensions
{
public static T LoadFromFileOrCreateDefault<T>(string path, JsonSerializerSettings settings = null) where T : new()
{
var serializer = JsonSerializer.CreateDefault(settings);
try
{
using (var file = File.OpenText(path))
{
return (T)JsonSerializer.CreateDefault(settings).Deserialize(file, typeof(T));
}
}
catch (FileNotFoundException)
{
return new T();
}
}
public static void SaveToFile<T>(T root, string path, Formatting formatting = Formatting.None, JsonSerializerSettings settings = null)
{
using (var file = File.CreateText(path))
using (var writer = new JsonTextWriter(file) { Formatting = formatting })
{
JsonSerializer.CreateDefault(settings).Serialize(writer, root);
}
}
}
Now you can add your Company to the array in CreateNewCompany() as follows:
var root = JsonExtensions.LoadFromFileOrCreateDefault<JObject>(Path);
var companiesArray = (JArray)root["Companies"] ?? (JArray)(root["Companies"] = new JArray());
companiesArray.Add(JObject.FromObject(company));
JsonExtensions.SaveToFile(root, Path, Formatting.Indented);
Demo fiddle #1 here.
Incidentally, since your entire file seems to have a fixed schema, you could simplify your code and get slightly better performance by deserializing directly to some root data model, omitting the JObject representation entirely.
First, create the following root data model:
public class CompanyList
{
public List<Company> Companies { get; } = new List<Company>();
}
Then modify CreateNewCompany() as follows:
var root = JsonExtensions.LoadFromFileOrCreateDefault<CompanyList>(Path);
root.Companies.Add(company);
JsonExtensions.SaveToFile(root, Path, Formatting.Indented);
Demo fiddle #2 here.
Notes:
By using generics in JsonExtensions we can use the same code to load from, and save to, a file, for both JObject and CompanyList.
Serializing directly from and to your file without loading to an intermediate string should improve performance as explained in Performance Tips: Optimize Memory Usage.
Company.StartDate is declared to be an int, however in your JSON it appears as a non-numeric string:
"StartDate": "1-1-2000"
You will need to adjust your data model to account for this.
There is no need to manually delete the old file as File.CreateText(String) creates or opens a file for writing UTF-8 encoded text. If the file already exists, its contents are overwritten.
Alternatively you might want to write to a temporary file and then overwrite the old file only after serialization finishes successfully.
It is better to catch the FileNotFoundException from File.OpenText() rather than checking File.Exists() manually in case the file is somehow deleted in between the two calls.
This should give you an idea of what you should be doing
public void CreateNewCompany()
{
Company company = new Company
{
CompanyName = "New Company",
IPO = Convert.ToDouble("0.2"),
Category = "Sample Category",
Description = "Sample Description",
StartDate = Convert.ToInt32("2009")
};
AddProductListItemsToFinishedJSON(company);
AddNewsArticlesListItemsToFinishedJSON(company);
SaveJSONFile(company);
}
public static void SaveJSONFile(Company localcompany)
{
if (File.Exists(path))
{
JObject arr = JObject.Parse(File.ReadAllText(path)));
(arr["Companies"] as JArray).Add(JToken.FromObject(localcompany));
string RawJSON = JsonConvert.SerializeObject(arr);
string FormattedJSON = JToken.Parse(RawJSON).ToString(Formatting.Indented);
File.WriteAllText(path, FormattedJSON);
}
else
{
JObject arr = new JObject();
arr.Add("Companies", new JArray());
(arr["Companies"] as JArray).Add(JToken.FromObject(localcompany));
string RawJSON = JsonConvert.SerializeObject(arr);
string FormattedJSON = JToken.Parse(RawJSON).ToString(Formatting.Indented);
File.WriteAllText(path, FormattedJSON);
}
}
Delete your existing json file then run this code. The first run creates the file with one object while subsequent runs adds object to it. You can refactor the code.
Json file will have the format below
{
"Companies": [
{
"Products": [],
"CompanySpecificNewsArticles": [],
"EavesDropperList": [],
"CompanyName": "New Company",
"IPO": 0.2,
"Category": "Sample Category",
"Description": "Sample Description",
"StartDate": 2009
},
{
"Products": [],
"CompanySpecificNewsArticles": [],
"EavesDropperList": [],
"CompanyName": "New Company",
"IPO": 0.2,
"Category": "Sample Category",
"Description": "Sample Description",
"StartDate": 2009
}
]
}
as per your comment on the order, you can set order on you class like below
public class Company
{
[JsonProperty(Order = 0)]
public string CompanyName { get; set; }
[JsonProperty(Order = 1)]
public double IPO { get; set; }
[JsonProperty(Order = 2)]
public string Category { get; set; }
[JsonProperty(Order = 3)]
public string Description { get; set; }
[JsonProperty(Order = 4)]
public int StartDate { get; set; }
[JsonProperty(Order = 5)]
public List<Product> Products = new List<Product>();
[JsonProperty(Order = 6)]
public List<NewsArticle> CompanySpecificNewsArticles = new List<NewsArticle>();
[JsonProperty(Order = 7)]
public List<string> EavesDropperList = new List<string>();
}

serializing nested json c#

Big apologies for the long post. I need to create the below json format for a post to rest api in c#. The below call works and I have used successfully in Postman to add it to the target system.
{
"item": {
"attrs": {
"attr": [{
"name": "IP_Category",
"value": "Miscellaneous"
}, {
"name": "Description",
"value": "Picture of Rabbit"
}, {
"name": "Title",
"value": "A Rabbit"
}
]
},
"resrs": {
"res": [{
"filename": "Rabbit.jpg",
"base64": "/9j/4AAQSkZJR"
}
]
},
"acl": {
"name": "Submitter"
},
"entityName": "IP_Document"
}
}
Based on the research I've done I need to copy and "paste special" into a new class file in visual studio so it can create the class objects based on the json format (Pretty cool!). And this is what it creates:
namespace BasicWebApp
{
public class Rootobject
{
public Item item { get; set; }
}
public class Item
{
public Attrs attrs { get; set; }
public Resrs resrs { get; set; }
public Acl acl { get; set; }
public string entityName { get; set; }
}
public class Attrs
{
public Attr[] attr { get; set; }
}
public class Attr
{
public string name { get; set; }
public string value { get; set; }
}
public class Resrs
{
public Re[] res { get; set; }
}
public class Re
{
public string filename { get; set; }
public string base64 { get; set; }
}
public class Acl
{
public string name { get; set; }
}
}
Problem 1: Why is vs renaming the res json object to to class Re? Is it a reserved word in c#?
Problem 2: I know I have to nest things in this fashion but I two levels deep and not sure what to code?
var model = new Rootobject();
model.item = new Item
{
attrs = new Attrs
{
attr = new List<Attr>
{
**now what??**
}
}
}
Don't have answer to your first question yet(but looking for it):
For your second question, at now what part you just do:
new Attr(){ name = "name1", value = "value1" },
new Attr(){ name = "name1", value = "value2" }
But that's not what i advise. I advise you to have your Attr collection ready then assign it. Like:
var model = new Rootobject();
model.item = new Item
{
attrs = yourAttrCollection
}
It also goes for everyting else you do. Have your stuff ready, then assign them. It increases readability in nested objects.
Problem 1: Why is vs renaming the res json object to to class Re? Is it a reserved word in c#?
No Re is not reserved word in class.
As mentioned by TheGeneral
res is plural for re's
You can use JsonProperty attribute to resolve this issue like
public class Resrs
{
[JsonProperty("res")]
public Re[] res { get; set; }
}
Problem 2: I know I have to nest things in this fashion but I two levels deep and not sure what to code?
var model = new Rootobject();
model.item = new Item
{
attrs = new Attrs
{
attr = new List<Attr>
{
new Attr { name = "abc", value = "ABC" },
new Attr { name = "pqr", value = "PQR" }
}
}
}
Thanks to all that responded. It helped. I ended up using the below code to create the json object I needed.
var model = new RootObject();
model.item = new Item
{
attrs = new Attrs
{
attr = new List<Attr>
{
new Attr { name = "IP_Category", value = ddlContent.Text },
new Attr { name = "Description", value = txtDesc.Text },
new Attr { name = "Title", value = txtTitle.Text }
}
},
resrs = new Resrs
{
res = new List<Re>
{
new Re { filename = fName, base64 = base64string},
}
},
acl = new Acl
{
name = "Submitter"
},
entityName = "IP_Document"
};

Issue with accessing json nodes from C#

I have a json file that needs to be saved as sql server table. This is test.json that has Student details with coursework.
[{
"Studentid": "001006360",
"Grade": "2",
"ExtraWork": {
"TopRecommended": ["000133692",
"102067155",
"887273865"],
"OtherCourses": ["228963647",
"138909237",
"899791144",
"216165613",
"113239563"]
},
"Courses": [{
"smalldesc": "this is a test ",
"Details": {
"description": "Summary of the course",
"collegeCode": "32466"
}
},
{
"smalldesc": "Second test",
"Details": {
"description": "Business- Course Summary",
"collegeCode": "32469"
}
}]
}]
Below is the C# program.
I do not know how to access "smalldesc" and "collegeCode".
var jsonText = File.ReadAllText(#"C:\test.json");
var ser = JsonConvert.DeserializeObject<List<RootObject>>(jsonText);
for (int i = 0; i < ser.Count; i++)
{
string Studentid = ser[i].Studentid;
string Grade = ser[i].Grade;
var result = JsonConvert.DeserializeObject<List<Course>>(jsonText);
for (int k = 0; k < result.Count; k++)
{
string smalldesc = result[k].smalldesc;
string collegeCode = result[k].Details.collegeCode;
}
}
Json object class definition:
public class ExtraWork
{
public List<string> TopRecommended { get; set; }
public List<string> OtherCourses { get; set; }
}
public class Details
{
public string description { get; set; }
public string collegeCode { get; set; }
}
public class Course
{
public string smalldesc { get; set; }
public Details Details { get; set; }
}
public class RootObject
{
public string Studentid { get; set; }
public string Grade { get; set; }
public ExtraWork ExtraWork { get; set; }
public List<Course> Courses { get; set; }
}
what's the best way to save to sql server tables.
This line:
var ser = JsonConvert.DeserializeObject<List<RootObject>>(jsonText);
Is already doing all the deserialization for you, there is no need to call it again inside a loop.
Your code can be as simple as this:
var ser = JsonConvert.DeserializeObject<List<RootObject>>(jsonText);
foreach (var s in ser)
{
string Studentid = s.Studentid;
string Grade = s.Grade;
foreach(var course in ser.Courses)
{
string smalldesc = course .smalldesc;
string details = course .Details.collegeCode;
}
}
FYI: using a foreach loop is much simpler to work with when iterating a collection (assuming your collection type implements IEnumerable which most of the included collections will).

Parsing JSON using LINQ

Hello I am facing a very simple problem but it is not getting Solved. Here is my class design
public class Program
{
public string ProgramName { get; set; }
public string ProgramTime { get; set; }
public string ProgramDetails { get; set; }
}
public class Listing
{
public string ChannelName { get; set; }
public string NowShowing { get; set; }
public string NowShowingTime { get; set; }
public string NowShowingDescription { get; set; }
public string NowShowingPicture { get; set; }
public List<Program> Programs { get; set; }
}
public class RootObject
{
public string status { get; set; }
public string about { get; set; }
public List<Listing> listings { get; set; }
}
I am parsing using the following code.
JObject json = JsonConvert.DeserializeObject(e.Result) as JObject;
Listing ls = new Listing
{
ChannelName = (string)json["listings"].Children()["ChannelName"],
NowShowing = (string)json["listings"].Children()["NowShowing"],
Programs = new Program
{
ProgramName = (string)json["listings"]["Program"]["ProgramName"]
}
};
Help me solve my lame approach. My concerns are parsing the items correctly and also how to add them to the nested list "Programs". The second one is more crucial.
Sample Json input-
{
"listings": [
{
"ChannelName": "NTV BANGLA",
"NowShowing": "Ei Shomoy (R)",
"NowShowingTime": "12:10",
"NowShowingDescription": "Ei Shomoy is a daily talk show ........",
"Programs": [
{
"ProgramName": "Ainer Chokhe (R)",
"ProgramTime": "13:00",
"ProgramDetails": "Human Rights and law based program Ainer Chokhe,"
},
{
"ProgramName": "Shonkhobash",
"ProgramTime": "15:10",
"ProgramDetails": "Drama serial Shonkhobash, script by Bipasha Hayat and"
}
]
},
{
"ChannelName": "CHANNEL i",
"NowShowing": "Taroka Kothon (Live)",
"NowShowingTime": "12:30",
"NowShowingDescription": "City Cell Taroka Kothon Live is a talk show ",
"Programs": [
{
"ProgramName": "Channel i Top News",
"ProgramTime": "13:00",
"ProgramDetails": "Mutual Trust Bank top news (Shirsho Shongbad)"
},
{
"ProgramName": "Ebong Cinemar Gaan",
"ProgramTime": "13:10",
"ProgramDetails": "Ebong Cinemar Gaan, a musical show based on "
}
]
}
]
}
EDIT1
var customers = JsonConvert.DeserializeObject<RootObject>(e.Result);
Listing ls = new Listing
{
ChannelName = customers.listings.First().ChannelName,
NowShowing=customers.listings.First().NowShowing,
Programs=??
};
if e.Result is string with your JSON try this
var jss = new JavaScriptSerializer();
var o = jss.Deserialize<RootObject>(e.Result);
UPDATE
possibly you need something like this
var customers = JsonConvert.DeserializeObject<RootObject>(e.Result);
Listing ls = new Listing
{
ChannelName = customers.listings.First().ChannelName,
NowShowing=customers.listings.First().NowShowing,
Programs=customers.listings.First().Programs
};
UPDATE2
if you want based on existing you can try comething like this
var customers = JsonConvert.DeserializeObject<RootObject>(e.Result);
Listing ls = new Listing
{
ChannelName = customers.listings.First().ChannelName,
NowShowing=customers.listings.First().NowShowing,
Programs=customers.listings.First().Programs.Select(p=>new Program{
ProgramName=p.ProgramName,
ProgramTime=p.ProgramTime,
ProgramDetails = p.ProgramDetails
}).ToList()
};
UPDATE3
or if you whant simply random you can try something like this
var customers = JsonConvert.DeserializeObject<RootObject>(e.Result);
Listing ls = new Listing
{
ChannelName = customers.listings.First().ChannelName,
NowShowing=customers.listings.First().NowShowing,
Programs=Enumerable.Range(1,10).Select(p=>new Program{
ProgramName="generated name",
ProgramTime="generated time",
ProgramDetails = "generated details"
}).ToList()
};
Use DataContractJsonSerializer to parse json string in windows phone.
MemoryStream memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(e.Result));
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(List<RootObject>));
RootObject itemDataList = dataContractJsonSerializer.ReadObject(memoryStream) as RootObject;
ChannelName = itemDataList.listings.First().ChannelName;

Categories

Resources