I have a json structured like that:
{
"eventType1": {
"unitName": "nameValue",
"comment": "initial comment"
},
"eventType2": {
"comment": "initial message"
},
}
When I deserialize it the appropriate type seems to be something like Dictionary<string, <Dictionary<string,string>>> and method would look like that:
public static Dictionary<string, Dictionary<string, string>> defaultFieldDataByEvent =
JsonConvert
.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(defaultFieldDataByEventSerialized);
which looks, well, ugly. But that's exactly how I need it to extract the data - defaultFieldDataByEvent[eventType][field].
Can I encapsulate the type into something somehow or is there a different approach to such cases?
I see multiple possible options here. Hope any of these helps.
You may try to add a type alias with using directive to make code shorter, but this won't be convenient, if logic is spread across multiple files, because you will be forced to duplicate this alias.
You may try to use JObject.Parse for deserialization, staying on lower level. But as far as your json structure is pretty various, this approach may work well.
You may try to deserialize your data into ExpandoObject. It's rather similar to JObject, except you will get pretty nice dynamic code (dynamic is not a problem here since compiler won't help you with Dictionary either), but it, obviously will be less performant. You could lose your custom types information, since everything in your graph will become an ExpandoObject, but seems like that's not an issue for your case. Example may be found here.
You may try to use [JsonExtensionData] as #dbc suggested. See How to serialize a Dictionary as part of its parent object using Json.Net.
Related
I have a set of objects that contain fields & properties that need to be inspectable in the output of serialization but not read back in when deserialized.
This is purely for debugging/confirmation purposes. We are creating hundreds of files and I want to spot check that serialization is occurring correctly by adding supplementary information. I do not want this supplementary information to be read in during deserialization - it's impossible to do so in fact.
I also need to do this with equal facility across different serialization formats, so we can assess which one is working best. I have a generic serialization approach where the desired format is passed in as an argument, so don't want anything too messy or intricate for each different format.
I've hunted around and found various things on related topics - mostly to do with the opposite: not writing certain fields during serialization. What's out there seems to be quite complicated and at times hacky.
Is it possible to serialize an object differently to deserializing it using Json.Net?
JsonConvert .NET Serialize/Deserialize Read Only
Serialize Property, but Do Not Deserialize Property in Json.Net
Also it appears any approach is inconsistent between serialization formats. i.e. unlike the [*Ignore] attributes, there are no [*SerializeOnly] attributes (where * = JSON, XML, YAML).
Is there an easy way to do this across these serialization formats? Is there a single family of attributes that can help? Or is it idiosyncratic and hacky in each case?
I have tested and applied this only to XML serialization, but it works for me:
When I want a property to be serialized, but not read back, I just declare an empty setter.
public String VersionOfApplicationThatHasWrittenThisFile
{
get
{
return "1.0";
}
set
{
// Leave empty
}
}
I am attempting to parse some JSON that has a known top level schema. However inside the schema is one JSON object that can contain various types of JSON objects.
Example
{
"knownfield1": data,
"knownfield2": data,
"knownfieldcollection":
{
"fieldofunknowntype1": "string data",
"fieldofunknowntype2":
{
"subunknownfield1": "string data",
"subunknownfield1": null
},
"fieldofunknowntype3": null
}
}
I would like to make an object that contains a mapping of the known fields, but can read the unknown fields in dynamically. I was trying with Json.Net JToken and JObject, but I could not get it to work. I kept getting recursive JToken exceptions.
Any pointers on this would be great. Thank you.
Exception I am getting:
Type 'Newtonsoft.Json.Linq.JToken' is a recursive collection data
contract which is not supported. Consider modifying the definition of
collection 'Newtonsoft.Json.Linq.JToken' to remove references to itself.
--edit--
Mistyped Collection for object, fixed that.
We have a winner. DBC hit the nail on the head. I had some left over WFC deserialization and it was causing problems. As soon I made sure all the DataContract code was completely cleared out and replaced everything with proper JSON.Net tags and calls, it worked wonderfully.
Thank you everyone for the support.
There are a couple of questions similar to this, on StackExchange, but they don't cover quite the same case. Please read it through before marking it as a duplicate!
Using CodeDom in C#, I'm trying to generate an Init Expression for a dictionary.
eg
Dictionary<int,string> dict = new Dictionary<int,string>{
{1,"one"},
{2,"two"}
};
I have found other solutions that use a CodeExpression to instantiate the object, and then several CodeStatements that populate the instance, but due to a bunch of boring reasons that's a path I'd rather not go down.
To clarify, since I can't use multiple CodeStatements, I kinda need to avoid generating something like this:
Dictionary<int,string> dict = new Dictionary<int,string>();
dict.Add(1,"one");
dict.Add(2,"two");
My question is: Is there a way to generate code like this using only CodeDom.CodeExpression(s)?
I'm pretty sure that at this point the answer is "no.", but thought it would be worth asking just in case.
As far as I can see, you can't express collection initializers in the CodeDOM object model. But there is a way to work around that: CodeSnippetExpression. Using that, you can create a string that directly contains any C# expression you want and use it inside another CodeDOM object.
You might be able to use the CodeDOM object model and GenerateCodeFromExpression() to get parts of the code you need (but you will certainly need to combine those parts by yourself).
No, if you want to use collection initializers you'll need to use LINQ Expressions instead of CodeDOM, e.g. System.Linq.Expressions.ListInitExpression.
I'm receiving messages over a network using JSON.NET. The message format is somewhat dynamic, in that the messages will be represented by many different classes, each inheriting from a parent message. For example:
{
MessageName: "MessageType1",
Data1: 124,
Data2: "Something"
}
{
MessageName: "MessageType2",
OtherData: "Some data",
MoreData: "Even more",
ANumber: 25
}
The problem I'm having is that in JSON.NET, I have no idea how to figure out the name of the class (MessageType1/MessageType2/etc) in order to deserialize it into an instance of the class without deserializing it twice. There's a few options I've considered; the one I'm currently using is to use a container class containing the message name and the actual json message serialized to string, but this seems wasteful.
Another method I've considered is deserializing into a string/string dictionary and then performing the population of the class on my own, which seems messy and unnecessary considering JSON.NET can do that for me... as long as I know the class first.
I'm really hoping there's an easy way to have JSON.NET figure out a class name by examining the MessageName property and then continue to populate a class after examining that one property.
Thanks for the help!
JSON can deserialize into a well known class only. You need to specify the data layout (i.e. the class/type)
There are two alternatives:
1.) go one level deeper. Use the JSON Token parser to read the tokens from your JSON stream and act based on the tokens you find.
2.) as you suggested: Use a class layout flexible enough to hold all your possible variations like a key/value dictionary.
Something I'm confusing.
The Javascript is going to produce the following JSON data.
{type:"book" , author: "Lian", Publisher: "ABC"}
{type:"Newspaper", author: "Noke"}
This is only an example, actually I've got more than this.
Since I have common fields between different JSON data, so I don't know is it possible to pass this to C# at one time.
What I want to do is pass this to c# then do some processing, what is the best way to do? I'm using ASP.NET MVC2.
Thanks for your answer or hints.
The combination of the 2 JSON statements above are, together, not valid JSON. That being said, you will not be able to use the JavaScriptSerializer class to deserialize that data into c# structure directly. Instead you will have to do some manual parsing first, to either break it down into valid JSON or just do full on manual parsing.
What I would actually recommend is sending over valid JSON instead. You can accomplish this by doing something like this:
{list: [
{type:"book" , author: "Lian", Publisher: "ABC"},
{type:"Newspaper", author: "Noke"} ]
Hard to say exactly, since only you know the details of your use case. You can send this data over using a traditional 'ajax' request. This is very easy to do with out any of the many JS libraries out there, but I would recommend just going with one anyway - they offer higher level constructs that are easier to use (and address cross-browser idiosyncrasies).
Since you are using ASP.NET MVC2, I would recommend jQuery. Microsoft is now backing jQuery as their JS library of choice and even make it default for new web projects.
Once you pass the above JSON to C#, you can deserialize it by doing something like this:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var result = serialzer.Deserialize<Dictionary<string, object>>(postedJSONData);
Your result will then have a structure that looks like this, in C#:
Dictionary<string, object> result =>
{ "list" => object },
object => List<object>,
List<object> => Dictionary<string, object>
{ "type" => "book", "author" => "Lian" } // etc
[
{type:"book" , author: "Lian", Publisher: "ABC"},
{type:"Newspaper", author: "Noke"}
]
Is still valid JSON (well actually keys need to be enclosed in " as well), so you can .push() into an array each time you create a JSON record.
var list = [];
// code doing other stuff
list.push({type:"book" , author: "Lian", Publisher: "ABC"});
// more code doing other stuff
list.push({type:"Newspaper", author: "Noke"})
Once your JSON list is constructed, you can send that list to the backend in one go.
You can also use the JavaScriptSerializer to deserialize your own custom type. Esentially you make a very simple type with all the properties of your json objects then call
JavaScriptSerializer serializer = new JavaScriptSerializer();
MyType result = serialzer.Deserialize<MyType>(JsonData);
You can also deserialize an array
MyType[] result = serialzer.Deserialize<MyType[]>(JsonData);