I am fairly new to programming (outside of a classroom environment).
I'm working on an application that has plugins. Each plugin packs/unpacks it's state (as a dictionary) and sends itself to be added to a dictionary containing all packed states. I'm using Json.Net to serialize/deserialize and pass off each plugin to it's own class to be packed/unpacked depending on if the project is being saved or opened.
The problem I'm having is when my first plugin gets its dictionary version of it's packed state to unpack, and I start going through the repopulating of each property, the first property (first item in the dictionary) is a DataTable. I'm getting an error saying:
Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to
type 'System.Data.DataTable'.
Here is my code for serializing.
IDictionary<string, IDictionary<string, object>> pluginStates =
new Dictionary<string, IDictionary<string, object>>();
signaller.RaiseSaveRequest(pluginStates); //gets all of the plugins' packedState
JsonSerializer serializer = new JsonSerializer();
serializer.ObjectCreationHandling = ObjectCreationHandling.Replace;
serializer.TypeNameHandling = TypeNameHandling.All;
using (StreamWriter sw = new StreamWriter(strPathName))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, pluginStates);
}
and deserializing.
IDictionary<string, IDictionary<string, object>> pluginStates =
new Dictionary<string, IDictionary<string, object>>();
JsonSerializer serializer = new JsonSerializer();
serializer.ObjectCreationHandling = ObjectCreationHandling.Replace;
serializer.TypeNameHandling = TypeNameHandling.All;
StreamReader sr = new StreamReader(fullName);
JsonTextReader reader = new JsonTextReader(sr);
string json = sr.ReadToEnd();
pluginStates = serializer.Deserialize<IDictionary<string, IDictionary<string, Object>>>(reader);
pluginStates = JsonConvert.DeserializeObject<IDictionary<string, IDictionary<string, Object>>>(json);
sr.Close();
reader.Close();
signaller.UnpackProjectState(pluginStates);
I've tried looking at the documentation on NewtonSoft.Json, but I barely understand it and how to make it work in my code. I'm thinking I need to do something with the Converters or Parsing once the plugin gets its packed state to unpack. When it was packed up, the plugin's 1st dictionary entry was saved as DataTable. Then, when in the Unpack, it's the actual dataTable in the value with the : separators.
I would provide screen shots, but I haven't figured out how to do that. Any ideas what I'm missing??
THANKS!
When a project is saved, the ProjMngr gets the packed pluginStates dictionary. I loop through each dictionary (plugin) within the pluginStates dictionary and create a dictionary holding the key, value(the json string version) and key, value(.net type). Add these to an array and put the array in the final projectState dictionary that gets serialized. Here's the code.
signaller.RaiseSaveRequest(pluginStates); <----has all plugin's packedState
//loop through plugins to get values and types
Dictionary<string, object> dictProjectState = new Dictionary<string, object>();
foreach (KeyValuePair<string,IDictionary<string,object>> plugin in pluginStates)
{
//holds jsonRepresented values
Dictionary<string, object> dictJsonRep = new Dictionary<string, object>();
//holds object types
Dictionary<string, object> dictObjRep = new Dictionary<string, object>();
object[] arrayDictHolder = new object[2]; //holds all of the dictionaries
string pluginKey = plugin.Key;
IDictionary<string, object> pluginValue = new Dictionary<string, object>();
pluginValue = plugin.Value;
foreach (KeyValuePair<string, object> element in pluginValue)
{
string jsonRepresentation = JsonConvert.SerializeObject(element.Value);
object objType = element.Value.GetType();
dictJsonRep.Add(element.Key, jsonRepresentation);
dictObjRep.Add(element.Key, objType);
}
arrayDictHolder[0] = dictJsonRep;
arrayDictHolder[1] = dictObjRep;
dictProjectState.Add(pluginKey, arrayDictHolder);
}
JsonSerializer serializer = new JsonSerializer();
using (StreamWriter sw = new StreamWriter(strPathName))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, dictProjectState);
}
Then when a project is opened, I did the same thing in reverse to get the pluginState back in it's original state to send off to each plugin. Used the type to make sure the type was right before sending. Realized I had to deserialize several times, which was surprising. I just couldn't get away from the Jarray or Jobject. But this works. Here's how I opened.
IDictionary<string, IDictionary<string, object>> pluginStates = new Dictionary<string, IDictionary<string, object>>();
StreamReader sr = new StreamReader(fullName);
JsonTextReader reader = new JsonTextReader(sr);
string json = sr.ReadToEnd();
var dictProjectState = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
sr.Close();
reader.Close();
foreach (var projectStatePair in dictProjectState)
{
string pluginKey = projectStatePair.Key; //key in pluginStates dict
Dictionary<string, object> dictJsonRep = new Dictionary<string, object>();
Dictionary<string, object> dictObjRep = new Dictionary<string, object>();
Dictionary<string, object> pluginValues = new Dictionary<string, object>();
string stpluginValue = projectStatePair.Value.ToString();
Newtonsoft.Json.Linq.JArray ja = (Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(stpluginValue);
object[] arrayHolder = ja.ToObject<object[]>();
string strArray0 = arrayHolder[0].ToString();
string strArray1 = arrayHolder[1].ToString();
dictJsonRep = JsonConvert.DeserializeObject<Dictionary<string, object>>(strArray0);
dictObjRep = JsonConvert.DeserializeObject<Dictionary<string, object>>(strArray1);
foreach (var pair in dictJsonRep)
{
string strVariableKey = pair.Key;
object objType = dictObjRep[pair.Key];
string jsonRep = (string)pair.Value;
Type jsonType = Type.GetType(objType as string);
object jsonReprValue = null;
jsonReprValue = JsonConvert.DeserializeObject(jsonRep, jsonType);
pluginValues.Add(strVariableKey, jsonReprValue);
}
pluginStates.Add(pluginKey, pluginValues);
}
signaller.UnpackProjectState(pluginStates);
Hopes this helps anyone looking for an answer.
Related
I have a list of Dictionary with same list of keys, but different value. Is there a way to write that to CSV file using the CSVHelper? I have the sample code below, but obviously it didn't work.
static void Main(string[] args)
{
List<Dictionary<String, String>> records = new List<Dictionary<string, string>>();
Dictionary<String, String> data1 = new Dictionary<String, String>();
data1.Add("Name1", "Value1");
data1.Add("Name2", "Value2");
records.Add(data1);
Dictionary<String, String> data2 = new Dictionary<String, String>();
data2.Add("Name1", "Value1");
data2.Add("Name2", "Value2");
records.Add(data2);
using (var writer = new StreamWriter("e:\\temp\\test.csv"))
using (var csv = new CsvWriter(writer))
{
csv.WriteRecords(records);
//GEtting exception here
//CsvHelper.Configuration.CsvConfigurationException: 'Types that inherit IEnumerable cannot be auto mapped. Did you accidentally call GetRecord or WriteRecord which acts on a single record instead of calling GetRecords or WriteRecords which acts on a list of records?'
}
}
Is there any way around that?
Thanks!
I believe the only way to do it will be to write them out by hand.
using (var writer = new StreamWriter("e:\\temp\\test.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
var headings = new List<string>(records.First().Keys);
foreach (var heading in headings)
{
csv.WriteField(heading);
}
csv.NextRecord();
foreach (var item in records)
{
foreach (var heading in headings)
{
csv.WriteField(item[heading]);
}
csv.NextRecord();
}
}
I have a dictionary Dictionary<int, string> of ints and strings, where ints are ids and strings are usernames, and when I convert it to JSON using Json.NET I get something like the following:
{"3":"jack","2":"john"}
I convert it like so:
Dictionary<int, string> dictFriends = new Dictionary<int, string>();
foreach (var id in resultList)
{
var user = db.Users.Find(id);
string friend = user.Username;
dictFriends.Add(id, friend);
}
string json = JsonConvert.SerializeObject(dictFriends);
But I am hoping to get something like so:
[
{ "id": "3", "user": "jack"},
{ "id": "2", "user": "john"},
]
Is it possible?
As far as I know you'd have to transform the dictionary into something JSON.NET would recognise as being an IEnumerable:
// YOUR DICTIONARY
var dictFriends = new Dictionary<int, string>() {
{1,"Jack"},
{2,"John"},
{3,"Jeff"}
};
// TRANSFORM INTO IENUMERABLE
var transformed = from key in dictFriends.Keys
select new { id = key, user = dictFriends[key] };
// SERIALIZE
var json = JsonConvert.SerializeObject(transformed);
Output:
[
{"id":1, "user":"Jack"},
{"id":2, "user":"John"},
{"id":3, "user":"Jeff"}
]
You're trying to use a Dictionary as an Array/List, writing to an existing key will overwrite it. Also your current key type is int therefore you would have JSON output such as
{1: "jack", 2: "john"}
Instead set your object type to List<Dictionary<string, Object>>
List<Dictionary<string, object>> friends = new List<Dictionary<string, Object>>();
foreach (var id in resultList)
{
var user = db.Users.Find(id);
string friend = user.Username;
Dictionary<string, object> dictFriend = new Dictionary<string, Object>();
dictFriend.Add("id", id);
dictFriend.Add("name" , friend);
friends.Add(dictFriend);
}
string json = JsonConvert.SerializeObject(friends);
You could use the DataContractJsonSerializer: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.datacontractjsonserializer(v=vs.110).aspx
The below will produce output in the form you're after; only instead of id and user your fields would be named key and value. The reason being those are the property names on the dictionary.
If you needed to change those names also (i.e. it's not just the structure you're interested in), you'd need to override the dictionary with a custom class, where you could add attributes such as [JsonProperty(PropertyName = "User")] to the properties to change how they're parsed... See http://www.newtonsoft.com/json/help/html/SerializationAttributes.htm for more.
Dictionary<int, string> dictFriends = new Dictionary<int, string>();
dictFriends.Add(1, "Alice");
dictFriends.Add(2, "Bob");
string jsonString;
using (MemoryStream ms = new MemoryStream()) {
//NB: DataContractJsonSerializer is in assembly System.Runtime.Serialization.dll - and others; http://stackoverflow.com/a/2682197/361842
DataContractJsonSerializer dcjs = new DataContractJsonSerializer(dictFriends.GetType());
dcjs.WriteObject(ms, dictFriends);
ms.Position = 0;
using(StreamReader sr = new StreamReader(ms)) {
jsonString = sr.ReadToEnd();
}
}
Debug.WriteLine(jsonString);
Sample output:
[{"Key":1,"Value":"Alice"},{"Key":2,"Value":"Bob"}]
can anyone advise how I should change my code (this is based on section 3.5.1.4.2 from the 3.0 developer manual). I am trying to create multiple nodes via one query in bolt.
using (var driver = GraphDatabase.Driver(Neo4jCredentials.Instance, AuthTokens.Basic(Neo4jCredentials.Username, Neo4jCredentials.Password)))
using (var session = driver.Session())
{
string query = "UNWIND { props } AS map CREATE(n) SET n = map";
Dictionary<string, object> myParameter = new Dictionary<string, object>();
myParameter.Add("props", "{\"props\":[{\"name\":\"Andres\",\"position\":\"Developer\"},{\"name\":\"Michael\",\"position\":\"Developer\"}]}");
return session.Run(query, myParameter);
}
The error I am getting is:
{"Expected map to be a map, but it was :`{\"props\":[{\"name\":\"Andres\",\"position\":\"Developer\"},{\"name\":\"Michael\",\"position\":\"Developer\"}]}`"}
Thanks in advance my learned friends...
Try forming your dictionary of params using an array of dictionaries:
Dictionary<string, object> myParameter = new Dictionary<string, object>();
Dictionary<string, object>[] props =
{
new Dictionary<string, object> {{"name", "Andres"}, {"position", "Developer"}},
new Dictionary<string, object> {{"name", "Michael"}, {"position", "Developer"}}
};
myParameter.Add("props",props);
or with a few less characters:
var myParameter = new Dictionary<string, object>
{
{
"props", new[]
{
new Dictionary<string, string> {{"name", "Andres"}, {"position", "Developer"}},
new Dictionary<string, string> {{"name", "Michael"}, {"position", "Developer"}}
}
}
};
I have a dynamic object whose property begins with number. How to access this property?
For inst:
myResult.123; // this is unvalid
Any helps would be very appreciated.
If you are using ExpandoObject for your dynamic object, you can cast to IDictionary<string, object> and use an indexer;
dynamic expando = new ExpandoObject();
var dict = (IDictonary<string, object>)expando;
dict["123"] = 2;
Many other dynamic object implementations (e. g. JObject in Json.NET) provide similar functionality.
Here's an example with JObject:
var json = JsonConvert.SerializeObject(new Dictionary<string, object> { { "123", 10 } });
var deserialized = JsonConvert.DeserializeObject<object>(json);
// using the IDictionary interface
var ten = ((IDictionary<string, JToken>)deserialized)["123"].Value<JValue>().Value;
Console.WriteLine(ten.GetType() + " " + ten); // System.Int64 10
// using dynamic
dynamic d = deserialized;
Console.WriteLine(d["123"].Value.GetType() + " " + d["123"].Value); // System.Int64 10
Modified
Type t = myResult.GetType();
PropertyInfo[] props = t.GetProperties();
Dictionary<string, object> dict = new Dictionary<string, object>();
foreach (PropertyInfo prp in props)
{
object value = GetPropValue(myResult, prp.Name);
dict.Add(prp.Name, value);
}
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
i need read whole resx file in code behind. I did this in this way:
ResXResourceReader rsxrOrganizationSubtypes = new ResXResourceReader(#"D:\DNN_Cafaas\DesktopModules\OPEGIEKA.DNN.Modules.CreateInstitution\App_LocalResources\OrganizationSubtypes.resx");
rsxrOrganizationSubtypes.UseResXDataNodes = true;
IDictionaryEnumerator dict = rsxrOrganizationSubtypes.GetEnumerator();
while (dict.MoveNext())
{
ResXDataNode node = (ResXDataNode)dict.Value;
}
Is there any possibility to sort/order results from resx file ? For example by Name ?
Resolved (sorted by value from resx file). Maybe there is better way to do it, but its working:
ResXResourceReader rsxr = new ResXResourceReader(PathToResX);
rsxr.UseResXDataNodes = true;
IDictionaryEnumerator dictRSXR = rsxr.GetEnumerator();
SortedDictionary<string, string> sortedRSXR = new SortedDictionary<string, string>();
while (dictRSXR.MoveNext())
{
ResXDataNode node = (ResXDataNode)dictRSXR.Value;
sortedRSXR.Add(node.GetValue((ITypeResolutionService)null).ToString(), node.Name);
}
foreach (KeyValuePair<string, string> p in sortedRSXR)
{
counterDDL++;
dropDownList.Items.Insert(counterDDL, new ListItem(p.Key, p.Value));
}
You could add keys and values to a SortedDictionary<string, ResXDataNode> in the while loop. This should sort your entries automatically.