I'm trying to deserialize a given JSON file in C# using a tutorial by Bill Reiss. For XML data in a non-list this method works pretty well, though I would like to deserialize a JSON file with the following structure:
public class Data
{
public string Att1 { get; set; }
public string Att2 { get; set; }
public string Att3 { get; set; }
public string Att4 { get; set; }
}
public class RootObject
{
public List<Data> Listname { get; set; }
}
My problem is with using JSON.Net's ability to create / put data into lists, and then displaying the list on an XAML page. My idea so far (which is not working):
var resp = await client.DoRequestJsonAsync<DATACLASS>("URL");
string t = resp.ToString();
var _result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<DATACLASS>>(t);
XAMLELEMENT.ItemsSource = _result;
So I think you're probably trying to deserialize to the wrong type. If you serialized it to RootObject and try to deserialize to List it's going to fail.
See this example code
public void TestMethod1()
{
var items = new List<Item>
{
new Item { Att1 = "ABC", Att2 = "123" },
new Item { Att1 = "EFG", Att2 = "456" },
new Item { Att1 = "HIJ", Att2 = "789" }
};
var root = new Root() { Items = items };
var itemsSerialized = JsonConvert.SerializeObject(items);
var rootSerialized = JsonConvert.SerializeObject(root);
//This works
var deserializedItemsFromItems = JsonConvert.DeserializeObject<List<Item>>(itemsSerialized);
//This works
var deserializedRootFromRoot = JsonConvert.DeserializeObject<Root>(rootSerialized);
//This will fail. YOu serialized it as root and tried to deserialize as List<Item>
var deserializedItemsFromRoot = JsonConvert.DeserializeObject<List<Item>>(rootSerialized);
//This will fail also for the same reason
var deserializedRootFromItems = JsonConvert.DeserializeObject<Root>(itemsSerialized);
}
class Root
{
public IEnumerable<Item> Items { get; set; }
}
class Item
{
public string Att1 { get; set; }
public string Att2 { get; set; }
}
Edit: Added complete code.
Related
I am building an API pulling data from Azure SQL would like to create a JSON array.
Currently I have an Azure Function written in C#.
Sample data looks like this:
I would like the output to look like this
My Azure Function is working fine, I just need to create an array. (I think)
await connection.OpenAsync();
SqlDataReader dataReader = await command.ExecuteReaderAsync();
var r = Serialize(dataReader);
json = JsonConvert.SerializeObject(r, Formatting.Indented);
I'm new to .NET and not sure quite where to begin. Thanks!
You could do it this way. Read the data into a Type that you can then use LINQ on to group into the desired shape, then serialize to JSON.
//Start with a list of the raw data by reading the rows into CardData list
List<CardData> cards = new List<CardData>();
while (dataReader.Read())
{
//You should check for DBNull, this example not doing that
cards.Add(new CardData
{
card_key = dataReader.GetString(0),
card_name = dataReader.GetString(1),
card_network = dataReader.GetString(2),
annual_fee = dataReader.GetDecimal(3),
speed_bonus_category = dataReader.GetString(4),
speed_bonus_amount = dataReader.GetInt32(5)
});
}
//Now transform the data into an object graph that will serialize
//to json the way you want. (flattens the redundant data)
var grp = cards.GroupBy(x => new { x.card_key, x.card_name, x.card_network, x.annual_fee });
var groupedData = new List<CardsModel>();
groupedData = grp.Select(g => new CardsModel
{
card_key = g.Key.card_key,
card_name = g.Key.card_name,
card_network = g.Key.card_network,
annual_fee = g.Key.annual_fee,
Bonuses = g.Select(b => new SpeedBonus
{
SpeedBonusCategory = b.speed_bonus_category,
SpeedBonusAmount = b.speed_bonus_amount
}).ToList()
}).ToList();
//Finally you can serialize
var json = JsonConvert.SerializeObject(groupedData, Formatting.Indented);
Here are the supporting classes you could use:
//represents the non-redundant object graph
public class CardsModel
{
public string card_key { get; set; }
public string card_name { get; set; }
public string card_network { get; set; }
public decimal annual_fee { get; set; }
public List<SpeedBonus> Bonuses { get; set; }
}
public class SpeedBonus
{
public string SpeedBonusCategory { get; set; }
public int SpeedBonusAmount { get; set; }
}
//represents raw data, has redundant cc info
public class CardData
{
public string card_key { get; set; }
public string card_name { get; set; }
public string card_network { get; set; }
public decimal annual_fee { get; set; }
public string speed_bonus_category { get; set; }
public int speed_bonus_amount { get; set; }
}
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"]);
}
}
I am trying to deserialize JSON file and want to assign to object ScanResult. var text showing all the values but scanresult showing null some null values. https://gyazo.com/ff2ce386f845394c458a88d43a1f30d8
please suggest if I am missing something.
//MY jSon File SCAN Test 1-1543045410222.json 's code
{
"at": 1543045410222,
"i": 1000,
"s": {
"Sensor1": ["OFF"],
"Sensor2": ["OFF"],
"DataReady1": ["OFF"],
"DataReady2": ["OFF"],
"CV1": [5.0],
"CV2": [6.0]
}
}
//ViewModel Code is as below:
public void ResendScanResult()
{
var ScanActivities = scanActivityManager.GetAll();
foreach (var item in ScanActivities)
{
var scanName = item.ScanName;
var dir = _dataFilePath + scanName + "\\";
var jsonFileName = string.Format("{0}{1}-{2}.json", dir, scanName, item.ScanDateEpoch);
string fileName = Path.GetFileName(jsonFileName);
// ScanResult scanResult = new ScanResult();
var text = File.ReadAllText(jsonFileName);
//var scanResults = JsonConvert.DeserializeObject<ScanResult>(text);
Common.Model.ScanResult scanResult = JsonConvert.DeserializeObject<Common.Model.ScanResult>(text);
var Mvm = MonitorViewModel.Instance;
// TargetProvider target = Mvm.GetTargetProvider(scanResult);
// Mvm.PublishToServer(target, scanResult);
}
}
and my scanRescult class code is as below :
namespace ABX.Common.Model
{
public class ScanResult
{
public ScanResult()
{
At = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Interval = 1;
}
public string Name { get; set; }
public long At { get; set; }
public long Interval { get; set; }
public JObject Values { get; set; }
public string FileName { get; set; }
public JObject ToJson()
{
JObject json = new JObject
{
{ "at", At },
{ "i", Interval },
{ "s", Values }
};
return json;
}
Either rename your class properties to match your JSON, rename your JSON to match your class properties, or implement a custom JsonConverter, where you can implement arbitrary mapping.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Images>
<I0>
<Path>123.com</Path>
<I0>
<I1>
<Path>123.com</Path>
<I1>
<I2>
<Path>123.com</Path>
<I2>
</Images>
Can serializer.Deserialize() be used to get tags with different names into a collection?
currently, in my object I have:
C#:
public class rootObject
{
[XmlElement(ElementName = "I0")]
public I0 I0 { get; set; }
[XmlElement(ElementName = "I1")]
public I1 I1 { get; set; }
[XmlElement(ElementName = "I2")]
public I2 I2 { get; set; }
}
But I would like to have (Because Images can have more or fewer elements):
public class rootObject
{
public List<I> Is { get; set; }
}
You can do what you are suggesting you just merely need to pass in the type argument in your class doing the generic. The key point to remember when you do a deserialization routine is that the routine needs to know the sub reference. So if I was to say string.Deserialize it would bomb. It would need to know a reference string.Deserialize> where Sub could be the class object that may change.
Say I have a base class and I want 'T' to be a type I can change for extensible abilities later.
[Serializable]
public class Test<T> where T : class
{
public Test() { }
public int TestId { get; set; }
public string Name { get; set; }
public List<T> Shipments { get; set; }
}
I want to test this with two classes I just make up that have different properties slightly
[Serializable]
public class Sub1
{
public int Id { get; set; }
public string Desc { get; set; }
}
[Serializable]
public class Sub2
{
public int IdWhatever { get; set; }
public string DescWhatever { get; set; }
}
Now let's do a main program and test serialization.
class Program
{
static void Main(string[] args)
{
var serializeTest = new Test<Sub1> { TestId = 1, Name = "Test", Shipments = new List<Sub1> { new Sub1 { Id = 1, Desc = "Test" }, new Sub1 { Id = 2, Desc = "Test2" } } };
var serializeTest2 = new Test<Sub2> { TestId = 1, Name = "Test", Shipments = new List<Sub2> { new Sub2 { IdWhatever = 1, DescWhatever = "Test" }, new Sub2 { IdWhatever = 2, DescWhatever = "Test2" } } };
var serialized = serializeTest.SerializeToXml();
var serialized2 = serializeTest2.SerializeToXml();
var deserialized = serialized.DeserializeXml<Test<Sub1>>();
var deserialized2 = serialized2.DeserializeXml<Test<Sub2>>();
Console.WriteLine(serialized);
Console.WriteLine();
Console.WriteLine(serialized2);
Console.ReadLine();
}
}
And my Serialize and DeSerialize extension methods:
public static string SerializeToXml<T>(this T valueToSerialize, string namespaceUsed = null)
{
var ns = new XmlSerializerNamespaces(new XmlQualifiedName[] { new XmlQualifiedName(string.Empty, (namespaceUsed != null) ? namespaceUsed : string.Empty) });
using (var sw = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
dynamic xmler = new XmlSerializer(typeof(T));
xmler.Serialize(writer, valueToSerialize, ns);
}
return sw.ToString();
}
}
public static T DeserializeXml<T>(this string xmlToDeserialize)
{
dynamic serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlToDeserialize))
{
return (T)serializer.Deserialize(reader);
}
}
You don't need to specify the XmlElement name when the properties match the XML. A few solutions, some kinda hacky :).
HACKY: use regex string replace to replace <I#> and </I#> to
just <I> and </I>
SOMEWHAT HACKY: This might work for you:
How to deserialize an XML array containing multiple types of elements in C#,
but you'd have to add an attribute for i0, i1 ... i100, etc.
BEST: Is that your entire XML? I'd honestly just use LINQToXml and
do a Descendants("Path") and get an array of strings back with 1 line of code. Serialization is not really the best solution for this.
So I have the json below that I want to Deseralize into Classes so I can work with it. But the issues is that the top two fields are a different type to all the rest
"items": {
"averageItemLevel": 718,
"averageItemLevelEquipped": 716,
"head": { ... },
"chest": { ... },
"feet": { ... },
"hands": { ... }
}
Where ... is a the Item class below, but the problem is that 2 of the fields are ints and the rest are Item, there are about 20 fields in total. So what I'd like to do is put them into a Dictionary<string, Item> but the 2 int fields are preventing me from Deseralizing it into that. I'm using JavaScriptSerializer.Deserialize<T>() to do this.
I could have each item as it's own class with the name of the item as the name of the class, but I find that to be very bad, repeating so much each time, also very hard to work with later since I cant iterate over the fields, where as I could a Dictionary. Any idea how I could overcome this?
public class Item
{
public ItemDetails itemDetails { get; set; }
public int id { get; set; }
public string name { get; set; }
public string icon { get; set; }
public int quality { get; set; }
public int itemLevel { get; set; }
public TooltipParams tooltipParams { get; set; }
public List<Stat> stats { get; set; }
public int armor { get; set; }
public string context { get; set; }
public List<int> bonusLists { get; set; }
}
Update: from the comments I came up with this solution
JObject jsonObject = JObject.Parse(json);
jsonObject["averageItemLevel"] = int.Parse(jsonObject["items"]["averageItemLevel"].ToString());
jsonObject["averageItemLevelEquipped"] = int.Parse(jsonObject["items"]["averageItemLevelEquipped"].ToString());
jsonObject["items"]["averageItemLevel"].Parent.Remove();
jsonObject["items"]["averageItemLevelEquipped"].Parent.Remove();
var finalJson = jsonObject.ToString(Newtonsoft.Json.Formatting.None);
var character = _serializer.Deserialize<Character>(finalJson);
character.progression.raids.RemoveAll(x => x.name != "My House");
return character
If I add these two classes to match your JSON I can serialize and deserialize the objects:
public class root
{
public Items items { get; set; }
}
public class Items
{
public int averageItemLevel { get; set; }
public int averageItemLevelEquipped { get; set; }
public Item head {get;set;}
public Item chest {get;set;}
public Item feet {get;set;}
public Item hands {get;set;}
}
Test rig with the WCF Serializer:
var obj = new root();
obj.items = new Items
{
averageItemLevel = 42,
feet = new Item { armor = 4242 },
chest = new Item { name = "super chest" }
};
var ser = new DataContractJsonSerializer(typeof(root));
using (var ms = new MemoryStream())
{
ser.WriteObject(ms, obj);
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
Console.WriteLine("and deserialize");
ms.Position = 0;
var deserializeObject = (root) ser.ReadObject(ms);
Console.WriteLine(deserializeObject.items.feet.armor);
}
And with the JavaScriptSerializer:
var jsser = new JavaScriptSerializer();
var json = jsser.Serialize(obj);
Console.WriteLine(json);
Console.WriteLine("and deserialize");
var djson = jsser.Deserialize<root>(json);
Console.WriteLine(djson.items.feet.armor);
Both serializers give the same result for your given JSON.