I am trying to deserialise JSON files that have been created by a third party tool.
The files contain a property that can look like the below:
"RECIPE": [{
"ctPoint_0": {
"endTemperature": 25,
"hours": 0.07999999821186066,
"startTemperature": 25
},
"ctPoint_1": {
"endTemperature": 30,
"hours": 0.07999999821186066,
"startTemperature": 25
},
"ctPoint_2": {
"endTemperature": 25,
"hours": 0.07999999821186066,
"startTemperature": 30
},
"pointCount": 3,
"type": "CyclicTemp"
}, {
"cycles": 2,
"type": "Repeat"
}, {
"cycles": 1,
"duration": {
"days": 0,
"hours": 0
},
}]
I am using system.text.json to deserialise:
newProgram = JsonSerializer.Deserialize<Program>(jsonString, options);
Extract of my Program class:
public class Program
{
public IList<Recipe> RECIPE { get; set; }
}
Recipe and cyclic_data struct:
public struct Cyclic_Data
{
public float endTemperature { get; set; }
public float hours { get; set; }
public float startTemperature { get; set; }
}
public struct Recipe
{
public int cycles { get; set; }
// Would like to use this
public IList<Cyclic_Data> ctPoints { get; set; }
// this deserialises ok but obviously only to hardcoded limit
public Cyclic_Data ctPoint_0 { get; set; }
public Cyclic_Data ctPoint_1 { get; set; }
public Cyclic_Data ctPoint_2 { get; set; }
public Cyclic_Data ctPoint_3 { get; set; }
public Cyclic_Data ctPoint_4 { get; set; }
public Cyclic_Data ctPoint_5 { get; set; }
public Cyclic_Data ctPoint_6 { get; set; }
public Cyclic_Data ctPoint_7 { get; set; }
public Cyclic_Data ctPoint_8 { get; set; }
public Cyclic_Data ctPoint_9 { get; set; }
public Cyclic_Data ctPoint_10 { get; set; }
public Duration duration { get; set;}
public string type { get; set; }
public float temperature { get; set; }
public int pointCount { get; set; }
}
As per the comments, if I have a number of discrete variables of type Cyclic_Data e.g. ctPoint_0 then this successfully deserialises, however as this list could theoretically be arbitrarily large it would be a nonsense to try to declare all possible property names.
I would really like to use an IList to read in all ctPoint_X values but am struggling to find a way to do so. I was looking at the newton soft implementation instead and wondering whether [JsonProperty("name")] could be used with RegEx to solve this but could not find any successful example done in this way.
How can I deserialise this in a sensible manner?
EDIT:
I am currently looking at a custom JsonNamingPolicy to rename any property name matching a RegEx "^ctPoint_[0-9]+$" to ctPoints, will let you know if this succeeds, please comment if this is doomed to fail or if there is a better way..
EDIT 2:
I tried the method outlined above but it didn't work as the correct JSON for a list of items doesn't have the name at beginning of each item, however this started me thinking about the problem differently. What I ended up doing was some simple string replacements before the deserialisation. This worked fine :)
int location;
location = newText.IndexOf("\"ctPoint_0\":");
newText = newText.Replace("\"ctPoint_0\":", "\"ctPoints\": [");
if (location > 0)
{ int lastloc;
for (int i = 1; i < 999999; i++)
{
string nextString = "\"ctPoint_" + i.ToString() + "\": ";
lastloc = location;
location = newText.IndexOf(nextString);
newText = newText.Replace(nextString, "");
if (location == -1)
{
location = newText.IndexOf("}", lastloc);
newText = newText.Insert(location+1, "]");
break;
}
}
}
Thanks
You can try Dictionary<string, object> and check the object type during runtime
Here are the models required for this scenario
public class CtPoint
{
public int endTemperature { get; set; }
public double hours { get; set; }
public int startTemperature { get; set; }
}
public class Duration
{
public int days { get; set; }
public int hours { get; set; }
}
Here is the sample code to Deserialize the JSON using System.Text.Json.JsonSerializer
var results = System.Text.Json.JsonSerializer.Deserialize<List<Dictionary<string,object>>>(json);
foreach (var model in results)
{
foreach(var item in model)
{
if (item.Key.Contains("ctPoint"))
{
var ctPoint = System.Text.Json.JsonSerializer.Deserialize<CtPoint>(item.Value.ToString());
Console.WriteLine($"{item.Key}- {ctPoint.hours} {ctPoint.startTemperature} {ctPoint.endTemperature}");
}
else if (item.Key.Contains("duration"))
{
var duration = System.Text.Json.JsonSerializer.Deserialize<Duration>(item.Value.ToString());
Console.WriteLine($"{item.Key}- {duration.days} {duration.hours}");
}
else
{
Console.WriteLine($"{item.Key}- {item.Value.ToString()}");
}
}
}
Output
ctPoint_0- 0,0799999982118607 25 25
ctPoint_1- 0,0799999982118607 25 30
ctPoint_2- 0,0799999982118607 30 25
pointCount- 3
type- CyclicTemp
cycles- 2
type- Repeat
cycles- 1
duration- 0 0
Related
I'm running into issues parsing a json reponse from GraphQL. The issue is the array will come back with more arrays half the time. My code is just getting out of hand and ugly.
Json file (trimmed it a bit. It can be 20+ data arrays)
{
"activity_logs": [
{
"data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"is_top_group\":false,\"pulse_id\":2165787062,\"pulse_name\":\"Tyler\",\"column_id\":\"email_address\",\"column_type\":\"email\",\"column_title\":\"Email Address\",\"value\":{\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"previous_value\":{\"email\":\"tyler#email.com\",\"text\":\"tyler#email.com\",\"changed_at\":\"2022-02-15T21:18:48.297Z\",\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"is_column_with_hide_permissions\":false,\"previous_textual_value\":\"tyler#email.com\"}"
},
{
"data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"is_top_group\":false,\"pulse_id\":216578711,\"pulse_name\":\"Nicholas \",\"column_id\":\"email_address\",\"column_type\":\"email\",\"column_title\":\"Email Address\",\"value\":{\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"previous_value\":{\"email\":\"nicholas#email.com\",\"text\":\"nicholas#email.com\",\"changed_at\":\"2022-02-16T04:44:52.046Z\",\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"is_column_with_hide_permissions\":false,\"previous_textual_value\":\"nicholas#email.com\"}"
},
{
"data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"is_top_group\":false,\"pulse_id\":216578711,\"pulse_name\":\"Nicholas \",\"column_id\":\"batch_5\",\"column_type\":\"text\",\"column_title\":\"Batch #\",\"value\":{\"value\":\"75\"},\"previous_value\":{\"value\":\"74\"},\"is_column_with_hide_permissions\":false}"
},
{
"data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"pulse_id\":216578711,\"is_top_group\":false,\"value\":{\"name\":\"Nicholas \"},\"previous_value\":{\"name\":\"Nicholas \"},\"column_type\":\"name\",\"column_title\":\"Name\"}"
}
]
}
Random "get it to work" attempt after giving up on making is a List based on a Class. The IContainers within IContainers were getting very complex.
var responseData = JObject.Parse(responseText).SelectToken("data").SelectToken("boards").SelectToken("activity_logs");
dynamic updatedRecords = JsonConvert.DeserializeObject(responseData.ToString());
foreach (var record in updatedRecords)
{
List<Dictionary<string, string>> records = new List<Dictionary<string, string>>();
Dictionary<string, string> fields = new Dictionary<string, string>();
dynamic updates = JsonConvert.DeserializeObject(JObject.Parse(record.ToString()).SelectToken("data").ToString());
foreach(var update in updates)
{
switch (update.Name.ToString())
{
case "column_id":
fields.Add(update.Name.ToString(), update.Value.ToString());
break;
case "pulse_name":
fields.Add(update.Name.ToString(), update.Value.ToString());
break;
case "value":
dynamic values = JsonConvert.DeserializeObject(JObject.Parse(update.Value.ToString()));
if (update.Name.ToString().Contains("column_settings"))
{
foreach (var value in values)
{
dynamic columns = JsonConvert.DeserializeObject(JObject.Parse(value.Value.ToString()));
foreach(var column in columns)
{
fields.Add($"Value_{column.Name.ToString()}", column.Value.ToString());
}
}
}
else
{
foreach (var value in values)
{
fields.Add($"Value_{value.Name.ToString()}", value.Value.ToString());
}
}
break;
case "previous_value":
dynamic prevValues = JsonConvert.DeserializeObject(JObject.Parse(update.Value.ToString()));
foreach (var prevalue in prevValues)
{
fields.Add($"Prevalue_{prevalue.Name.ToString()}", prevalue.Value.ToString());
}
break;
case "previous_textual_value":
fields.Add(update.Name.ToString(), update.Value.ToString());
break;
}
}
if (fields.Count > 0)
{
records.Add(fields);
fields.Clear();
}
}
My Error when I get to:
dynamic values = JsonConvert.DeserializeObject(JObject.Parse(update.Value.ToString()));
- $exception {"The best overloaded method match for 'Newtonsoft.Json.JsonConvert.DeserializeObject(string)' has some invalid arguments"} Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
Solution is a big help and led to my answer. The issue is the activity_logs data comes with escape characters in it so the string contains \\".
I had to format the data sections with Replace("\\", "") and Replace("\"{", "{") and Replace("}\""), "}"). This made the string readable as a Json file.
You have to pass in a string to DeserializeObject instead of a JSON object.
Another way would be get your JSON mapped to a POCO types as follows, easy way to do is on Visual Studio (Copy your JSON contents, on Visual Studio create a new empty class -> Edit-> Past Special -> Paste JSON as classes)
public class LogsRoot
{
public Activity_Logs[] activity_logs { get; set; }
}
public class Activity_Logs
{
public string data { get; set; }
}
public class DataRoot
{
public long board_id { get; set; }
public string group_id { get; set; }
public bool is_top_group { get; set; }
public long pulse_id { get; set; }
public string pulse_name { get; set; }
public string column_id { get; set; }
public string column_type { get; set; }
public string column_title { get; set; }
public Value value { get; set; }
public Previous_Value previous_value { get; set; }
public bool is_column_with_hide_permissions { get; set; }
public string previous_textual_value { get; set; }
}
public class Value
{
public Column_Settings column_settings { get; set; }
}
public class Column_Settings
{
public bool includePulseInSubject { get; set; }
public bool ccPulse { get; set; }
public string bccList { get; set; }
}
public class Previous_Value
{
public string email { get; set; }
public string text { get; set; }
public DateTime changed_at { get; set; }
public Column_Settings1 column_settings { get; set; }
}
public class Column_Settings1
{
public bool includePulseInSubject { get; set; }
public bool ccPulse { get; set; }
public string bccList { get; set; }
}
Then load the JSON and manipulate as follows,
var json = File.ReadAllText("data.json");
var rootLogs = JsonConvert.DeserializeObject<LogsRoot>(json);
Dictionary<string, string> fields = new Dictionary<string, string>();
foreach (var logJson in rootLogs.activity_logs)
{
var log = JsonConvert.DeserializeObject<DataRoot>(logJson.data);
fields.Add(log.column_id, log.value.column_settings.bccList + log.value.column_settings.ccPulse);
fields.Add(log.pulse_name, log.value.column_settings.bccList + log.value.column_settings.ccPulse);
fields.Add(log.previous_value.email, log.value.column_settings.bccList + log.value.column_settings.ccPulse);
fields.Add(log.previous_textual_value, log.value.column_settings.bccList + log.value.column_settings.ccPulse);
}
This might not solve all your issues, but for the specific exception you are running into, it is because you are trying to deserialize a JObject instead of string.
Probably you just want:
dynamic values = JsonConvert.DeserializeObject(update.Value.ToString());
using MessagePack;
[MessagePackObject]
public class CPegar_ids
{
[Key(0)]
public string operationName { get; set; }
[Key(1)]
public Variables variables { get; set; }
[Key(2)]
public string query { get; set; }
}
[MessagePackObject]
public class Variables
{
[Key(0)]
public object activeType { get; set; }
[Key(1)]
public string[] instruments { get; set; }
[Key(2)]
public string leverageInstrument { get; set; }
[Key(3)]
public int userGroupID { get; set; }
[Key(4)]
public string sortField { get; set; }
[Key(5)]
public string sortDirection { get; set; }
[Key(6)]
public int limit { get; set; }
[Key(7)]
public int offset { get; set; }
}
string json_data = #"
{
""operationName"": ""GetAssets"",
""variables"": {
""activeType"": null,
""instruments"": [
""BinaryOption"",
""DigitalOption"",
""FxOption"",
""TurboOption""
],
""leverageInstrument"": ""BinaryOption"",
""userGroupID"": 193,
""sortField"": ""Name"",
""sortDirection"": ""Ascending"",
""limit"": 20,
""offset"": 0
},
""query"": """"
}
";
var ob_ids = MessagePackSerializer.Deserialize<CPegar_ids>(Encoding.UTF8.GetBytes(json_data ));
Console.WriteLine($" IDS OB: {ob_ids.GetType()}");
https://github.com/neuecc/MessagePack-CSharp
I'm downloading JSON with HttpWebRequest, which returns a var string. I want to use this string to Deserialize with MessagePackSerializer. I've tried several different ways, with Utf8Json I can do it, but with this MessagePack I can't. I want to use MessagePack because it is much faster.
It looks like MessageBack have their own notation which is not JSON. But you're trying to deserialize Json into their custom notation which fails for obvious reasons. They seem to keep it small an compact by using more unicode in place of standard characters like JSON.
see https://msgpack.org/index.html
This is why you're not going to make it work putting in a JSON string and trying to deserialize it. If you're looking for faster JSON options there are a few other common alternatives to Newtonsoft Json.NET such as fastJSON https://github.com/mgholam/fastJSON
Reversing your sample code we can get an example of what the serialized values look like:
var myObject = new CPegar_ids {
operationName = "GetAssets",
variables = new Variables {
activeType = null,
instruments = new string[] {
"BinaryOption",
"DigitalOption",
"TurboOption"
},
leverageInstrument = "BinaryOption",
userGroupID = 193,
sortField = "Name",
sortDirection = "Ascending",
limit = 20,
offset = 0
},
query = ""
};
var bytes = MessagePackSerializer.Serialize(myObject);
Console.WriteLine(Encoding.UTF8.GetString(bytes));
the output of which is:
��operationName�GetAssets�variables��activeType��instruments��BinaryOption�DigitalOption�TurboOption�leverageInstrument�BinaryOption�userGroupID���sortField�Name�sortDirection�Ascending�limit14�offset00�query�
I couldn't find a good explanation on why it is not working. But there is a way to make it work instead of using Key(int index) attribute we will use Key(string propertyName) attribute.
Should you use an indexed (int) key or a string key? We recommend
using indexed keys for faster serialization and a more compact binary
representation than string keys. Reference.
OBJECTS
[MessagePackObject]
public class CPegar_ids
{
[Key("operationName")]
public string operationName { get; set; }
[Key("variables")]
public Variables variables { get; set; }
[Key("query")]
public string query { get; set; }
}
[MessagePackObject]
public class Variables
{
[Key("activeType")]
public object activeType { get; set; }
[Key("instruments")]
public string[] instruments { get; set; }
[Key("leverageInstrument")]
public string leverageInstrument { get; set; }
[Key("userGroupID")]
public int userGroupID { get; set; }
[Key("sortField")]
public string sortField { get; set; }
[Key("sortDirection")]
public string sortDirection { get; set; }
[Key("limit")]
public int limit { get; set; }
[Key("offset")]
public int offset { get; set; }
}
SERIALIZATION
var jsonByteArray = MessagePackSerializer.ConvertFromJson(File.ReadAllText("json1.json"));
CPegar_ids ob_ids = MessagePackSerializer.Deserialize<CPegar_ids>(jsonByteArray);
I got some Json, that looks like this:
[
{
"starttime": "2020-02-27T14:30:00Z",
"endtime": "2020-02-27T14:40:00Z"
},
{
"Temp": {
"value": 3
},
"Pressure": {
"value": 29
},
"Humidity": {
"value": 85
}
}
]
I would like to deserialize it onto a object on the form:
public class Sample {
public string Name {get; set;}
public int Value {get;set;}
}
and then get 3 instances where name is set to either Temp, Pressure, Humidity, and Value set to 3, 29, 85
I don't really care about the start-/endtime part.
Any help would be greatly appreciated...
/Søren
Update:
Came up with this myself:
var tmp = JsonConvert.DeserializeObject<JArray>(content);
var samples = tmp.
SelectMany(x => ((JToken) x).Children())
.Where(x => !((JProperty) x).Name.Contains("time"))
.Select(x =>
{
var tmp2 = x.First.ToObject<Sample>();
tmp2.name = ((JProperty) x).Name;
return tmp2;
})
.ToList();
but I think Pavel's solution below, is more readable....
You can use Json.Linq to get a list of Sample objects from your json. Parse json to JArray instance, then enumerate all properties of the last object to get the names and values
var array = JArray.Parse(json);
var samples = ReadSamples(array.Last());
foreach (var sample in samples)
{
Console.WriteLine($"{sample.Name} {sample.Value}");
}
IEnumerable<Sample> ReadSamples(JToken data)
{
foreach (JProperty item in data)
{
yield return new Sample()
{
Name = item.Name,
Value = item.Value["value"]?.Value<int>() ?? 0
};
}
}
The output will be the following
Temp 3
Pressure 29
Humidity 85
It's also possible to do the same using System.Text.Json API, which is available from .NET Core 3.x
Per your posted JSON, you would get a model like below. Use http://json2csharp.com/#
public class Temp
{
public int value { get; set; }
}
public class Pressure
{
public int value { get; set; }
}
public class Humidity
{
public int value { get; set; }
}
public class RootObject
{
public DateTime starttime { get; set; }
public DateTime endtime { get; set; }
public Temp Temp { get; set; }
public Pressure Pressure { get; set; }
public Humidity Humidity { get; set; }
}
If your JSON is not dynamic, creating classes which model your JSON is a good idea.
An easy way is to Copy JSON to clipboard -> Open Visual Studio -> Edit -> Paste Special -> Paste JSON as classes.
This should give you the following classes:
public class Class1
{
public DateTime starttime { get; set; }
public DateTime endtime { get; set; }
public Temp Temp { get; set; }
public Pressure Pressure { get; set; }
public Humidity Humidity { get; set; }
}
public class Temp
{
public int value { get; set; }
}
public class Pressure
{
public int value { get; set; }
}
public class Humidity
{
public int value { get; set; }
}
And now you can deserialize the JSON array to List<Class1>using the Newtonsoft.Json NuGet package:
using Newtonsoft.Json;
using System.Collections.Generic;
...
string json = #"[
{
""starttime"": ""2020 - 02 - 27T14: 30:00Z"",
""endtime"": ""2020-02-27T14:40:00Z""
},
{
""Temp"": {
""value"": 3
},
""Pressure"": {
""value"": 29
},
""Humidity"": {
""value"": 85
}
}
]";
var myObject = JsonConvert.DeserializeObject<List<Class1>>(json);
I use the mongoDB C# driver 2.1.1 to store and retrieve documents in a mongoDb collection. This worked well so far until one document was CORRECTLY stored but could not be read back by the driver.
I got to that conclusion using robomongo (a user interface to monitor what's inside my collection) and manipulating the object stored.
It contains a collection of elements (around 4000 sub elements) and if I remove enough of it, the document is finally retrievable again.
The line of code used is:
public Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
{
return MongoQueryable.FirstOrDefaultAsync(_collection, predicate, cancellationToken);
}
Before you ask, what I first thought is that one specific element of my sub elements set had encountered some issues while being serialized/deserialized and was creating the issue. I tested by removing randomly elements of the collection, and just the number seems to be the root of the problem.
The text file size of the Json document represents around 11 Mb - I will try now to get the actual size of the object which would be more relevant.
Something else I can add is that in the mondoDb log file, there is one line that only appear when I try to select an "oversized" document :
2016-06-29T19:30:45.982+0200 I COMMAND [conn12] command MYCOLLECTIONDb.$cmd command: aggregate
{ aggregate: "XXXX", pipeline: [ { $match: { _id: "5773e0e9a1152d259c7d2e50" } }, { $limit: 1 } ]
, cursor: {} } keyUpdates:0 writeConflicts:0 numYields:0 reslen:4188200 locks:{ Global:
{ acquireCount: { r: 6 } }, MMAPV1Journal: { acquireCount:
{ r: 3 } }, Database: { acquireCount: { r: 3 } }, Collection: { acquireCount: { R: 3 } } } 109ms
(XXXX being my custom object)
So I'd like to know if you have any idea of what's causing this issue, any hint of where I should try to look, because I am running out of ideas :)
EDIT_1: That is basically the structure of my object :
[DataContract]
public class MyClass
{
[DataMember]
public string _id { get; set; }
[DataMember]
public string XmlPreference { get; set; }
[DataMember]
public string XmlMarketDates { get; set; }
[DataMember]
public IEnumerable<ClassB> Lines { get; set; }
}
[DataContract]
public class ClassB
{
[DataMember]
public string UniqueId { get; set; }
[DataMember]
public string ParentId { get; set; }
[DataMember]
public Dictionary<string, ClassC> DataMapping {get; set;}
}
and ClassC is just a container of 7 ints and 1 object properties.
Still looking for something :)
EDIT 2: I reproduced the bug only using the mongoDb C# drivers 2.1.1 release version. Here is the code :
using MongoDB.Bson;
using MongoDB.Driver.Linq;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace TestingMongoDbCsharpDriver
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Debugging starting...");
try
{
MongoDB.Driver.MongoClient myClient = new MongoDB.Driver.MongoClient("mongodb://localhost:27010");
var db = myClient.GetDatabase("DocumentStoreDb");
var collection = db.GetCollection<DocumentModel>("TestOverload");
Console.WriteLine("Collection TestOverload found");
Random rand = new Random(999999999);
DocumentModel toInsert = null;
for (int lineNb = 1; lineNb < 50000; lineNb += 1000)
{
string id = rand.Next().ToString();
Console.WriteLine(string.Format("\nCreating document with id '{0}' and {1} lines...", id, lineNb));
toInsert = Funcs.Create(id, lineNb);
Console.WriteLine("Created.");
// Saving and waiting for it to finish
collection.InsertOneAsync(toInsert).Wait();
Console.WriteLine("Inserted.");
// retrieving it
var filter = new BsonDocument("_id", new BsonDocument("$eq", id));
var cursor = collection.FindAsync<DocumentModel>(filter).Result;
cursor.MoveNextAsync().Wait();
string messFilterMethod = cursor.Current.Count() == 1 ? "Retrieved" : "Not retrieved. Bug confirmed";
Console.WriteLine("With Filter: " + messFilterMethod);
var model = MongoQueryable.FirstOrDefaultAsync(collection.AsQueryable(), e => e._id == id).Result;
string mess = model != null ? "Retrieved" : "Not retrieved. Bug confirmed";
Console.WriteLine("With AsQueryable: " + mess);
// Removing it
collection.DeleteOneAsync(filter).Wait();
Console.WriteLine("Deleted.\n");
Console.ReadKey();
}
}
catch (Exception e)
{
Console.WriteLine("\n\nERROR: " + e.Message);
}
Console.WriteLine("\n\n**************** NO BUG *************\n");
}
}
public static class Funcs
{
public static DocumentModel Create(string uniqueId, int nbLines)
{
Random random = new Random(2000000);
List<MyDocumentSubElement> listOk = new List<MyDocumentSubElement>();
for (int lines = 0; lines < nbLines; ++lines)
{
Dictionary<string, SnapCellValueStyle> newDico = new Dictionary<string, SnapCellValueStyle>();
for (int i = 0; i < 10; ++i)
{
int idSnap = random.Next();
var snap = new SnapCellValueStyle()
{
alignment = idSnap,
Value = "okkkkkkkkkkzzzzkk"
};
newDico.Add("newKey_" + idSnap.ToString(), snap);
}
MyDocumentSubElement doc = new MyDocumentSubElement()
{
Icon = 516,
Name = "name du truc",
ParentId = "parent id",
type = SubElementType.T3,
UniqueId = "uniqueId_" + random.Next().ToString(),
MapColumnNameToCellValue = newDico
};
listOk.Add(doc);
}
int headerId = random.Next();
MyDocumentHeader temp = new MyDocumentHeader()
{
Comment = "comment",
Date = DateTime.Now,
ExtractionId = headerId,
Id = "id ok _ " + headerId,
Name = "Name really interesting name",
OwnerId = 95115,
RootFolioId = 51,
SnapshotViewId = MyDocumentType.Type2
};
DocumentModel toInsert = new DocumentModel()
{
_id = uniqueId,
Header = temp,
XmlMarketDates = "<xmlPrefok65464f6szf65ze4f6d2f1ergers5fvefref3e4f05e4f064z68f4xd35f8eszf40s6e40f68z4f0e8511xf340ed53f1d51zf68d4z61ef644dcdce4f64zef84zOKok>><>>",
XmlPreference = "<<zefaiunzhduiaopklzpdpakzdplapdergergfdgergekâzda4684z16ad84s2dd0486za04d68a04z8d0s1d d4az80d46az4d651s1d8 154efze40f6 4ze65f40 65ze40f6z4e>><>>>",
Lines = listOk
};
return toInsert;
}
}
// Imitation of SnapshotDocModel
[DataContract]
public class DocumentModel
{
[DataMember]
public string _id { get; set; }
[DataMember]
public MyDocumentHeader Header { get; set; }
[DataMember]
public string XmlPreference { get; set; }
[DataMember]
public string XmlMarketDates { get; set; }
[DataMember]
public IEnumerable<MyDocumentSubElement> Lines { get; set; }
}
[DataContract]
public class MyDocumentHeader
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public int OwnerId { get; set; }
[DataMember]
public string Comment { get; set; }
[DataMember]
public DateTime Date { get; set; }
[DataMember]
public int RootFolioId { get; set; }
[DataMember]
public MyDocumentType SnapshotViewId { get; set; }
[DataMember]
public int ExtractionId { get; set; }
}
[DataContract]
public class MyDocumentSubElement
{
[DataMember]
public string UniqueId { get; set; }
[DataMember]
public string ParentId { get; set; }
[DataMember]
public int Icon { get; set; }
[DataMember]
public SubElementType type { get; set; }
[DataMember]
public Dictionary<string, SnapCellValueStyle> MapColumnNameToCellValue { get; set; }
[DataMember]
public string Name { get; set; }
}
public class SnapCellValueStyle
{
public object Value { get; set; }
public int alignment { get; set; }
public int Red { get; set; }
public int Green { get; set; }
public int Blue { get; set; }
public int currency { get; set; }
public int decimalPoint { get; set; }
public int kind { get; set; }
public int style { get; set; }
}
#region enum
public enum MyDocumentType
{
Undefined,
Type1,
Type2,
Type3,
Type4,
Type5
}
public enum SubElementType
{
T1,
T2,
T3
}
#endregion
}
If you test it, you will see that there is the point where the AsQueryable method does not work anymore where as the document is still retrievable by the method using a filter.
Problem fixed in the version 2.2.4 of the c# mongo db driver (probably with the bug https://jira.mongodb.org/browse/CSHARP-1645)
Thanks :)
I'm trying to retrieve values that are stored in a JSON string that I obtain from a website using Newtonsoft.Json.
I have the code below, but I cant work out how to loop through the data to retrieve the Name tag within the Palette->Threads->Name section. The number of thread names may vary from 1 to 15.
The desired outcome of the code below would be to output something like
Colours Used: Black, Light Blue, White etc
Any help would be much appreciated, I've racked my brains looking at other peoples examples, but I've had no luck in applying Dictionary or Lists (I'm still learning .net)
protected void Page_Load(object sender, EventArgs e)
{
string jsondata = "{\"Width\":295,\"Height\":329,\"NumStitches\":1596,\"NumTrims\":1,\"Left\":479,\"Top\":-868,\"Right\":775,\"Bottom\":-539,\"Recipe\":\"Normal\",\"MachineFormat\":\"Tajima\",\"MasterDensity\":40,\"Palette\":{\"Threads\":[{\"Name\":\"Black\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1000\",\"Red\":0,\"Green\":0,\"Blue\":0,\"Type\":\"ttRayon\",\"Thickness\":3},{\"Name\":\"Light Blue\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1029\",\"Red\":0,\"Green\":114,\"Blue\":207,\"Type\":\"ttRayon\",\"Thickness\":3},{\"Name\":\"White\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1001\",\"Red\":255,\"Green\":255,\"Blue\":255,\"Type\":\"ttRayon\",\"Thickness\":3},{\"Name\":\"Mustard Brown\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1165\",\"Red\":255,\"Green\":153,\"Blue\":51,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Midnight Blue\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1242\",\"Red\":0,\"Green\":40,\"Blue\":120,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Jungle Green\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1249\",\"Red\":0,\"Green\":204,\"Blue\":0,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Robin Egg Blue\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1093\",\"Red\":0,\"Green\":255,\"Blue\":255,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Hyacinth\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1112\",\"Red\":125,\"Green\":0,\"Blue\":153,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Aztec Gold\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1125\",\"Red\":255,\"Green\":240,\"Blue\":51,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Evergreen\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1303\",\"Red\":0,\"Green\":73,\"Blue\":51,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Lilac\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1033\",\"Red\":153,\"Green\":0,\"Blue\":153,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Jet Black\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1000\",\"Red\":0,\"Green\":0,\"Blue\":0,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Sapphire\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1076\",\"Red\":0,\"Green\":87,\"Blue\":150,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Bordeaux\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1035\",\"Red\":99,\"Green\":47,\"Blue\":61,\"Type\":\"ttCotton\",\"Thickness\":3},{\"Name\":\"Flesh\",\"Manufacturer\":\"Madeira 40\",\"Code\":\"1017\",\"Red\":244,\"Green\":188,\"Blue\":172,\"Type\":\"ttCotton\",\"Thickness\":3}]},\"Needles\":[1,2,3]}";
var output = JsonConvert.DeserializeObject<jsonclass>(jsondata);
int StitchCount = output.NumStitches;
int StitchHeight = output.Height;
int StitchWidth = output.Width;
var pal = output.Palette;
// The following code is wrong, but illustrates what I'm trying to do
Response.Write("Colours used: ");
foreach (thread in pal["Threads"])
{
Response.Write(thread["Name"] & ",");
}
}
public class jsonclass
{
public int Width { get; set; }
public int Height { get; set; }
public int NumStitches { get; set; }
public Object Palette { get; set; }
}
I've stripped it down a bit, but this is a visual representation of the JSON data to help understand it
{
"Width":295,
"Height":329,
"NumStitches":1596,
"Palette":
{
"Threads":
[
{
"Name":"Black",
"Manufacturer":"Madeira 40",
"Code":"1000",
"Red":0,
"Green":0,
"Blue":0,
"Type":"ttRayon",
"Thickness":3
},
{
"Name":"Light Blue",
"Manufacturer":"Madeira 40",
"Code":"1029",
"Red":0,
"Green":114,
"Blue":207,
"Type":"ttRayon",
"Thickness":3
},
{
"Name":"White",
"Manufacturer":"Madeira 40",
"Code":"1001",
"Red":255,
"Green":255,
"Blue":255,
"Type":"ttRayon",
"Thickness":3
}
]},
"Needles":[1,2,3]
}
You should model your JsonClass as follow and add threads etc. as well:
public class JsonClass
{
public int Width { get; set; }
public int Height { get; set; }
public int NumStitches { get; set; }
public Palette Palette { get; set; }
}
public class Palette
{
public IEnumerable<Thread> Threads { get; set; }
}
public class Thread
{
public string Name { get; set;}
...
}
Then you can iterate over the threads with the following code:
foreach (var thread in pal.Threads)
{
Response.Write(thread.Name + ", ");
}
use the following model to Deserialise your json.
public class Palette
{
public List<Thread> Threads { get; set; }
}
public class Thread
{
public string Name { get; set; }
public string Manufacturer { get; set; }
public string Code { get; set; }
public int Red { get; set; }
public int Green { get; set; }
public int Blue { get; set; }
public string Type { get; set; }
public int Thickness { get; set; }
}
public class Colors
{
public int Width { get; set; }
public int Height { get; set; }
public int NumStitches { get; set; }
public Palette Palette { get; set; }
public List<int> Needles { get; set; }
}
On page load
var output = JsonConvert.DeserializeObject<Colors>(jsondata);
then iterate the thread
foreach(var thread in output.Palette.Threads){
//something like you wanted
Response.Write(thread.Name + ",");
}
Solution using JSON.NET built-in LINQ to JSON provider:
JObject jObject = JObject.Parse(jsondata);
JArray threads = (JArray)jObject["Palette"]["Threads"];
var colorsUsed = new StringBuilder();
colorsUsed.Append("Colours used: ");
foreach (var thread in threads)
{
colorsUsed.AppendFormat("{0}, ", thread["Name"]);
}
Response.Write(colorsUsed);