Accessing Data sets from Json - c#

I am mapping JSON data to my own classes in C# and then trying to display various data where I need it however I'm having a small issue where I can't seem to get at data when I believe I should be able to. Obviously something is wrong and I was hoping someone could point me in the right direction:
Example snippet of JSON:
"items"
{
"0"
{
"name" "Riki's Dagger"
"prefab" "default_item"
"item_name" "#DOTA_Item_Rikis_Dagger"
"item_type_name" "#DOTA_WearableType_Daggers"
"model_player" "models/heroes/rikimaru/rikimaru_weapon.mdl"
"used_by_heroes"
{
"npc_dota_hero_riki" "1"
}
}
"1"
{
"name" "Anti-Mage's Glaive"
"prefab" "default_item"
"item_description" "#DOTA_Item_Desc_AntiMages_Glaives"
"item_name" "#DOTA_Item_AntiMages_Glaive"
"item_type_name" "#DOTA_WearableType_Glaive"
"model_player" "models/heroes/antimage/antimage_weapon.mdl"
"used_by_heroes"
{
"npc_dota_hero_antimage" "1"
}
}
I am using the following to serialize this to my own classes as follows:
DotaItemsGameResult itemGameResult
= JsonConvert.DeserializeObject<DotaItemsGameResult>(rawItemDetailsJson);
This is working OK as I have used this elsewhere.
The trouble comes here:
string dataToDisplay = "";
foreach (DotaItemsGameItem item in itemGameResult.Items_Game.Items.Item_Index)
{
dataToDisplay += "<h3> Item: " + item.Name + "</h3>";
dataToDisplay += "<p> Quality: " + item.Item_Quality + "</p>";
dataToDisplay += "<p> Attributes: " + item.Used_By_Heroes + "</p>";
}
return dataToDisplay;
My code seems to know about itemGameResult.Items_Game.Items but not when I want to go further into .Items_Index.
I have the following classes:
public class DotaItemsGameResult
{
public DotaItemsGameResultProperties Items_Game { get; set; }
}
public class DotaItemsGameResultProperties
{
public List<DotaItemsGameRarities> Rarities { get; set; }
public List<DotaItemsGameItems> Items { get; set; }
}
public class DotaItemsGameItems
{
public List<DotaItemsGameItem> Item_Index { get; set; }
}
public class DotaItemsGameItem
{
public string Name { get; set; }
public string Hidden { get; set; }
public string Item_Class { get; set; }
public string Item_Name { get; set; }
public string Item_Slot { get; set; }
public string Item_Quality { get; set; }
public string Min_Ilevel { get; set; }
public string Max_Ilevel { get; set; }
public string Item_Description { get; set; }
public string Item_Type_Name { get; set; }
public List<DotaItemsGameUsedByHero> Used_By_Heroes { get; set; }
}
Basically, my aim is to be able to get at the Used_By_Heroes data in my loop but I can't.
In my for each, itemGameResult.Items_Game.Items is fine, but itemGameResult.Items_Game.Items.Item_Index is not and I can't see why.
I can't access the the Item_Index when I use dot notation, there's no Item_Index where I would expect there to be. If I put it in anyway and try to compile, I see this:
Error 1 'System.Collections.Generic.List' does not contain a definition for 'Item_Index' and no extension method 'Item_Index' accepting a first argument of type 'System.Collections.Generic.List' could be found (are you missing a using directive or an assembly reference?).
Any help would be fantastic.

Problem is that the Items property of the class DotaItemsGameResultProperties is a collection (List<DotaItemsGameItems>) so it doesn't have a property Item_Index. Not sure what do you want to achieve, but one possibility to fix this is to iterate on this collection also:
string dataToDisplay = "";
foreach (DotaItemsGameItems items in itemGameResult.Items_Game.Items)
{
foreach (DotaItemsGameItem item in items.Item_Index)
{
dataToDisplay += "<h3> Item: " + item.Name + "</h3>";
dataToDisplay += "<p> Quality: " + item.Item_Quality + "</p>";
dataToDisplay += "<p> Attributes: " + item.Used_By_Heroes + "</p>";
}
}
return dataToDisplay;
This is to illustrate the structure of your data, you can do this in a more concise way:
string dataToDisplay = "";
var allItems = itemGameResult.Items_Game.Items.SelectMany(i => i.Item_Index);
foreach (DotaItemsGameItem item in allItems)
{
dataToDisplay += "<h3> Item: " + item.Name + "</h3>";
dataToDisplay += "<p> Quality: " + item.Item_Quality + "</p>";
dataToDisplay += "<p> Attributes: " + item.Used_By_Heroes + "</p>";
}
return dataToDisplay;

Related

How to read property names on related list

With these models:
public class Course
{
public Guid Id { get; set; }
public string Title { get; set; }
public IList<CourseEvent> CourseEvents { get; set; }
}
public class CourseEvent
{
public Guid Id { get; set; }
public Guid CourseId { get; set; }
public DateTime StartDate { get; set; }
}
...and this method:
private void WritePropertyNames(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
Console.WriteLine(item.Name + " => " + item.GetValue(obj, null));
}
}
...I can get the property names and values on any object provided:
var course = new Course { Title = "My course", CourseEvents = new List<CourseEvent>() { new() { StartDate = DateTime.Today }, new() { StartDate = DateTime.Today.AddDays(-1) } } };
WritePropertyNames(course);
But how do I get the related CourseEvents property names and values too? I've tried this, but that's not right:
foreach (var item2 in obj.GetType().GetProperty("CourseEvents").GetType().GetProperties())
{
Console.WriteLine(item2.Name + " => " + item2.GetValue(obj, null));
}
It might be ugly and not optimal and won't work for all the cases (quickly wrote it just to demonstrate the idea)
So you could check if property is Generic by item.PropertyType.IsGenericType, you could also check if it type implements IEnumerable typeof(IEnumerable).IsAssignableFrom(item.PropertyType). Then you could get the underlying type using item.PropertyType.GenericTypeArguments[0]. Then it basically becomes your logic that you have - you iterating over objects and getting props as you already have
private static void WritePropertyNames(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
if(item.PropertyType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(item.PropertyType))
{
var innerProps = item.PropertyType.GenericTypeArguments[0].GetProperties();
foreach(var innerItem in item.GetValue(obj, null) as IEnumerable)
{
foreach(var innerProp in innerProps)
{
Console.WriteLine(item.Name + " => " + innerProp.Name + " => " + innerProp.GetValue(innerItem, null));
}
}
}
else
{
Console.WriteLine(item.Name + " => " + item.GetValue(obj, null));
}
}
}

How to take FirstName and LastName in DropDown List

In controller I have this code and at this moment I have DropDown list just for firstname.
Code is here:
ViewBag.patnikID = new SelectList(db.tbl_patnici, "pID", "firstname");
And now I need some code like this:
ViewBag.patnikID = new SelectList(db.tbl_patnici, "pID", ("firstname" + "lastname"));
How to do it?
Your tbl_patnici class
public class tbl_patnici
{
public int pID { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
//[NotMapped] If you use entityframework then you must use NotMapped attribute.
public string fullname { get { return this.firstname + " " + this.lastname; } }
}
ViewBag.patnikID = new SelectList(db.tbl_patnici, "pID", "fullname");
I would suggest you don't bind directly to the database source and instead bind to your own IEnumerable which has the properties you want. I often have a reusable "ListItem" class which has ID and Text properties and then use a function to populate the list with the data I want.
For example:
Create a new class:
public class ListItem
{
public int ID { get; set; }
public string Text { get; set; }
}
Create a helper function:
public List<ListItem> GetList()
{
// get "db" here.
return db.tbl_patnici.Select(x => new ListItem {
ID = x.pID,
Text = x.firstname + " " + x.lastname
});
}
Call it like so:
ViewBag.patnikID = new SelectList(GetList(), "ID", "Text");
You can check this:
#Html.DropDownListFor(model => model.pID, new SelectList(db.tbl_patnici, "pID", Model.firstname + " " + Model.lastname, Model.pID), new { style = " width:260px" })

Parse Json data from Twitter ASP.NET C# - null data unless parsed into type object

So I have successfully parsed data from numerous API's but I can't seem to get (some of) the twitter one working.
I am pulling from the endpoint "/1.1/statuses/user_timeline.json"
The json data I am having a problem with is the following (see https://dev.twitter.com/overview/api/entities for more info):
"entities":{
"hashtags": [
{"text":"myHasTag","indices":[24,53]}
],
"symbols":[],
"user_mentions":[
{"screen_name":"twitter","name":"Twitter","id":2353,"id_str":"2353","indices":[5,14]},
{"screen_name":"TwitterDev","name":"TwitterDev","id":943434,"id_str":"943434","indices":[11,32]}
],
"urls":[]
}
I'd like to extract the hastags and user_mentions but they both come up as null when I parse the data in using a JavaScriptSerializer.
In my Model I have the following:
public partial class TwitterData_Entities
{
List<TwitterData_HashTag> hashtags { get; set; }
List<TwitterData_UserMentions> user_mentions { get; set; }
}
public partial class TwitterData_HashTag
{
public string text { get; set; }
public List<int> indices { get; set; }
}
public partial class TwitterData_UserMentions
{
public string screen_name { get; set; }
public string name { get; set; }
public long id { get; set; }
public List<int> indices { get; set; }
}
I have also tried adding the line below to each object in TwitterData_Entities but it made no difference
[JsonProperty(PropertyName = "user_mentions")]
the only thing that works and populates is by using:
public partial class TwitterData_Entities
{
List<object> hashtags { get; set; }
List<object> user_mentions { get; set; }
}
The problem is that I don't want to use the "object" type as it wont work for my purposes and it also creates inconsistency in my data structure too.
What do you guys suggest to fix the problem? I can't find anything online.
I managed to deserialize it the following way:
var json = "{" +
" \"entities\": {" +
" \"hashtags\": [" +
" {" +
" \"text\": \"myHasTag\"," +
" \"indices\": [ 24, 53 ]" +
" }" +
" ]," +
" \"symbols\": [ ]," +
" \"user_mentions\": [" +
" {" +
" \"screen_name\": \"twitter\"," +
" \"name\": \"Twitter\"," +
" \"id\": 2353," +
" \"id_str\": \"2353\"," +
" \"indices\": [ 5, 14 ]" +
" }," +
" {" +
" \"screen_name\": \"TwitterDev\"," +
" \"name\": \"TwitterDev\"," +
" \"id\": 943434," +
" \"id_str\": \"943434\"," +
" \"indices\": [ 11, 32 ]" +
" }" +
" ]," +
" \"urls\": [ ]" +
" }" +
"}";
var javascriptSerializer = new JavaScriptSerializer();
var deserialized = javascriptSerializer.Deserialize<TwitterData>(json);
This is just the JSON you provided nested in { ... } to make it a valid JSON and the actual deserialization.
My classes are the following:
public class TwitterData_Entities
{
public List<TwitterData_HashTag> hashtags { get; set; }
public List<TwitterData_UserMentions> user_mentions { get; set; }
}
public class TwitterData_HashTag
{
public string text { get; set; }
public List<int> indices { get; set; }
}
public class TwitterData_UserMentions
{
public string screen_name { get; set; }
public string name { get; set; }
public long id { get; set; }
public List<int> indices { get; set; }
}
public class TwitterData
{
public TwitterData_Entities entities { get; set; }
}
The important thing is to use the public access modifier for the properties of the TwitterData_Entities class.

How do I access list inside an object [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
How can I read the values inside H_N1_N2,H_N1_N3,H_N1_N4 that calls from H_N1_N1.
My objective is to put all the values into List that contains another object inside.
The requirement is to eliminate the current process which is storing the values to temp table in database before validation. After validated, it goes to the physical table.
Here's my entities:
public class H_N1_N1
{
public string N101_EntityIdentifierCode { get; set; }
public string N102_Name { get; set; }
public string N103_IdentificationCodeQualifier { get; set; }
public string N104_IdentificationCode { get; set; }
public H_N1_N1()
{
ListH_N1_N2 = new List<H_N1_N2>();
ListH_N1_N3 = new List<H_N1_N3>();
ListH_N1_N4 = new List<H_N1_N4>();
}
public List<H_N1_N2> ListH_N1_N2 { get; set; }
public List<H_N1_N3> ListH_N1_N3 { get; set; }
public List<H_N1_N4> ListH_N1_N4 { get; set; }
}
public class H_N1_N2
{
public string N201_Name01 { get; set; }
public string N202_Name02 { get; set; }
}
public class H_N1_N3
{
public string N301_AddressInformation01 { get; set; }
public string N302_AddressInformation02 { get; set; }
}
public class H_N1_N4
{
public string N401_CityName { get; set; }
public string N402_StateProvinceCode { get; set; }
public string N403_PostalCode { get; set; }
public string N404_CountryCode { get; set; }
}
Here's how I populate my object:
var N1_N1 = dal.GetModelDetails(11);
for (int i = 0; i < Convert.ToInt16(N1_N1.MaxLoop); i++)
{
H_N1_N1 oH_N1_N1 = new H_N1_N1();
stElements = ResizeArray(stElements.Count(), stElements, "H_N1_N1");
oH_N1_N1.N101_EntityIdentifierCode = stElements[1];
oH_N1_N1.N102_Name = stElements[2];
oH_N1_N1.N103_IdentificationCodeQualifier = stElements[3];
oH_N1_N1.N104_IdentificationCode = stElements[4];
objH_N1_N1.Add(oH_N1_N1);
var N1_N2 = dal.GetModelDetails(12);
H_N1_N2 oH_N1_N2 = new H_N1_N2();
stElements = ResizeArray(stElements.Count(), stElements, "H_N1_N2");
oH_N1_N2.N201_Name01 = stElements[1];
oH_N1_N2.N202_Name02 = stElements[2];
oH_N1_N1.ListH_N1_N2.Add(oH_N1_N2);
var N1_N3 = dal.GetModelDetails(14);
H_N1_N3 oH_N1_N3 = new H_N1_N3();
stElements = ResizeArray(stElements.Count(), stElements, "H_N1_N3");
oH_N1_N3.N301_AddressInformation01 = stElements[1];
oH_N1_N3.N302_AddressInformation02 = stElements[2];
oH_N1_N1.ListH_N1_N3.Add(oH_N1_N3);
var N1_N4 = dal.GetModelDetails(16);
H_N1_N4 oH_N1_N4 = new H_N1_N4();
stElements = ResizeArray(stElements.Count(), stElements, "H_N1_N4");
oH_N1_N4.N401_CityName = stElements[1];
oH_N1_N4.N402_StateProvinceCode = stElements[2];
oH_N1_N4.N403_PostalCode = stElements[3];
oH_N1_N4.N404_CountryCode = stElements[4];
}
There's the part where I cannot read the object:
foreach (var oH_N1_N1 in objH_N1_N1)
{
MessageBox.Show(
// Print N1
oH_N1_N1.N101_EntityIdentifierCode
+ "\n" + oH_N1_N1.N102_Name
+ "\n" + oH_N1_N1.N103_IdentificationCodeQualifier
+ "\n" + oH_N1_N1.N104_IdentificationCode
// Print N2
oH_N1_N1.ListH_N1_N2.N201_Name01 //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N2.N201_Name02 //ERROR HERE
// Print N3
oH_N1_N1.ListH_N1_N3.N301_AddressInformation01 //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N3.N301_AddressInformation02 //ERROR HERE
// Print N4
oH_N1_N1.ListH_N1_N4.N401_CityName //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N4.N402_StateProvinceCode //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N4.N403_PostalCode //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N4.N404_CountryCode //ERROR HERE
);
}
This is what i am trying to do:
N1_somedata
N1_somedata
N1_somedata
N1_somedata
N2_somedata
N2_somedata
N3_somedata
N3_somedata
N4_somedata
N4_somedata
N4_somedata
N4_somedata
N1_somedata
N1_somedata
N1_somedata
N1_somedata
N2_somedata
N2_somedata
N3_somedata
N3_somedata
N4_somedata
N4_somedata
N4_somedata
N4_somedata
N1_somedata
N1_somedata
N1_somedata
N1_somedata
N2_somedata
N2_somedata
N3_somedata
N3_somedata
N4_somedata
N4_somedata
N4_somedata
N4_somedata
Thanks in advance!
OP, this code makes me want to weep for little children, but the reason you're getting errors is because you're placing 4 separate variables in MessageBox.Show() call and not tying them together.
Update
Based on your comment,
when I try to type oH_N1_N1.ListH_N1_N2, there is no N201_Name01 and N201_Name02
That's because oH_N1_N1.ListH_N1_N2 is a List<H_N1_N2> property. You cannot access properties of H_N1_N2 that way. You have to access via the list, for example using the indexer:
oH_N1_N1.ListH_N1_N2[0].N201_Name01
You can also do foreach to get all of the elements...
string crazyNames = string.Empty;
foreach(var crazyName in oH_N1_N1.ListH_N1_N2)
{
crazyNames += crazyName.N201_Name01 + " " + N201_Name02 // etc.
}
Notice the [0] above which is the first element in the list. Now, the intellisense will show you available properties of the stored object, which is an instance of H_N1_N2 and will contain the property N201_Name01 and so on.
Original issue / answer:
Add + signs there and it'll work.
For the love of humanity please use some different naming conventions!
foreach (var oH_N1_N1 in objH_N1_N1)
{
MessageBox.Show(
// Print N1
oH_N1_N1.N101_EntityIdentifierCode
+ "\n" + oH_N1_N1.N102_Name
+ "\n" + oH_N1_N1.N103_IdentificationCodeQualifier
+ "\n" + oH_N1_N1.N104_IdentificationCode
+ // concatenate next object to first one
// Print N2
oH_N1_N1.ListH_N1_N2.N201_Name01 //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N2.N201_Name02 //ERROR HERE
+ // concatenate next object to first+second one
// Print N3
oH_N1_N1.ListH_N1_N3.N301_AddressInformation01 //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N3.N301_AddressInformation02 //ERROR HERE
+ // concatenate last object to first+second+third one
// Print N4
oH_N1_N1.ListH_N1_N4.N401_CityName //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N4.N402_StateProvinceCode //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N4.N403_PostalCode //ERROR HERE
+"\n" + oH_N1_N1.ListH_N1_N4.N404_CountryCode //ERROR HERE
);
}

Using StreamWriter to write to different files in a Parallel.Foreach

I am attempting to write separate collections to seperate csv in a Parallel.Foreach loop. When I run this, I get the following error:
The process cannot access the file 'C:\temp\OCRProcess\2011\49\OCRProcess-2011-49.csv' because it is being used by another process.
When I look at all the worker processes, they are opening different files, none of them are using the same file location. From what I can tell, each thread (worker process) is not conflicting.
public void GenerateCSVFile(List<CSVFile> csvFiles)
{
Parallel.ForEach(csvFiles, (csvfile, state, index) =>
{
var fileLocation = _storageLocation + csvfile.Type + s + csvfile.Year + s + csvfile.Day + s + csvfile.Type + "-" +
csvfile.Year + "-" + csvfile.Day + ".csv";
if (!File.Exists(fileLocation))
{
File.Create(fileLocation);
}
using (var streamWriter = new StreamWriter(fileLocation))
{
foreach (var csvRecord in csvfile.CSVRecords)
{
streamWriter.WriteLine(csvRecord.Object_Id + "," + csvRecord.DocumentName + "," + csvRecord.BCI_DCN + "," + csvRecord.CreationDate);
}
}
});
}
Here is the CSVFile and CSVRecord classes just incase.
public sealed class CSVRecord
{
public String BCI_DCN { get; set; }
public String Object_Id { get; set; }
public String DocumentName { get; set; }
public String CreationDate { get; set; }
}
public sealed class CSVFile
{
public List<CSVRecord> CSVRecords { get; set; }
public String Year { get; set; }
public String Type { get; set; }
public String Day { get; set; }
public CSVFile()
{
CSVRecords = new List<CSVRecord>();
}
}
The issues is due to File.Create(fileLocation), which returns a FileStream and keeps the file open. When the StreamWriter attempted to open this, it was already open and caused the error.
To correct the problem, removed the following IF statement:
if (!File.Exists(fileLocation))
{
File.Create(fileLocation);
}
And updated the USING statement as followed. By adding the TRUE parameter, it allows StreamWriter to append to the file if it exists, otherwise create it.
using (var streamWriter = new StreamWriter(fileLocation, true))
{
foreach (var csvRecord in csvfile.CSVRecords)
{
streamWriter.WriteLine(csvRecord.Object_Id + "," + csvRecord.DocumentName + "," + csvRecord.BCI_DCN + "," + csvRecord.CreationDate);
}
}

Categories

Resources