This question already has answers here:
How do I get json.net to serialize members of a class deriving from List<T>?
(3 answers)
Closed 6 years ago.
I can't find a way to serialize with JSON.NET a list of derived lists, and I'm starting to wonder if it's even possible. Let me explain the situation with some code.
I've created a new class which is derived from a list of a specific object (tried first with a generic one) and added a string property NomGroupe:
public class GroupeActes : List<Acte>
{
public string NomGroupe { get; set; }
public GroupeActes(string nom, List<Acte> liste)
{
NomGroupe = nom;
foreach (var acte in liste)
{
this.Add(acte);
}
}
}
Then, in my code, I've declared a list of this class (List<GroupeActes> listOfGroupeActes) and I fill it with data. For the serialization, I use this code:
JsonSerializer serializer = new JsonSerializer();
serializer.TypeNameHandling = TypeNameHandling.All;
using (StreamWriter sw = new StreamWriter(#"listOfGroupeActes.json"))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, listOfGroupeActes);
}
I've tried with and without the TypeNameHandling.All parameter and with several combination of Json.net properties and even with DataContract/DataMember.
So far, I only managed to get in my json file either the data of each nested List<Acte> without the NomGroupe property, or the other way around. But not both, which is what I'd like to have.
Two questions then:
Is it even possible?
If yes, how can I do it?
Thanks for your help!
You don't want to inherit from List<T>.
Create a list property instead:
public class GroupeActes
{
public List<Acte> Actes { get; set; }
public string NomGroupe { get; set; }
public GroupeActes(string nom, List<Acte> liste)
{
NomGroupe = nom;
Actes.AddRange(acte);
}
}
Lists (and other collection types) get special treatment while serializing. You don't want the collection type's public properties (such as Capacity and Count) in your output, so the property you added through inheritance won't be serialized either.
A collection is serialized like this:
if o is IEnumerable
foreach object s in o
serialize o
So the serializer won't even look at your enumerable's properties.
Try to use Newtonsoft Json.NET
string itemToSend = JsonConvert.SerializeObject(dataModel);
Related
In my application I use the following code to serialze objects:
private static string Serialize(Type type, object objectToSerialize)
{
StringBuilder builder = new StringBuilder();
using (TextWriter writer = new StringWriter(builder))
{
XmlSerializer serializer = new XmlSerializer(type);
serializer.Serialize(writer, objectToSerialize);
}
return builder.ToString();
}
This code just worked fine until now.
We've introduced a new class which looks like:
[Serializable]
public class Restriction
{
public string Id { get; set; }
public ResticType Type { get; set; }
public Restriction Parent { get; set; }
public List<Restriction> Children { get; set; }
}
If I try to serialize it I get the following exception:
A circular reference was detected while serializing an object of type Restriction
I already found out, that this occures because of the Parent and the Children which are also of type Restriction
I've already tried to set the Parent-Property to NonSerialized but this doesn't work.
Unfortunately I can not change the code for serialization...
What can I do to serialize this class?
Actual my only idea is to implement IXmlSerializable in my Restriction-class and do the reading and writing of the xml by my own. I hope there is another way...
I've already tried to set the Parent-Property to NonSerialized but this doesn't work.
NonSerialized is for binary serialization. Use XmlIgnore instead.
Note that you'll have to manually restore the Parent property after deserialization:
void RestoreParentRelationship(Restriction restriction)
{
foreach (var child in restriction.Children)
child.Parent = restriction;
}
This question already has answers here:
Why doesn't XmlSerializer support Dictionary?
(3 answers)
Closed 9 years ago.
i'm using this class
public class Branch
{
public string Name { get; set; }
public User Manager { get; set; }
public User Secretary { get; set; }
public Dictionary<string, User> Broker;
public Dictionary<string, Apartment> Apartments;
public Branch()
{}
public Branch(Branch other)
{
Name = other.Name;
Manager = other.Manager;
Secretary = other.Secretary;
Broker = other.Broker;
Apartments = other.Apartments;
}
}
trying to run this line : Dict2XML.Save_Branch2XML(Branchs);
through this method:
static public void Save_Branch2XML(Dictionary<string, Branch> D)
{
//List<KeyValuePair<string, User>> DictionList = D.ToList();
List<Branch> DictionList = D.Select(p => new Branch(p.Value)).ToList<Branch>();
XmlSerializer Serializer = new XmlSerializer(DictionList.GetType());
TextWriter writer = new StreamWriter(#"C:\Users\tzach_000\Documents\Visual Studio 2013\Projects\RealEstate\RealEstate\DB\XMLBranch.xml");
Serializer.Serialize(writer, DictionList);
writer.Close();
}
and the program collapse when it gets to the XmlSerializer line in save_branch2xml method.
The XmlSerializer doesn't support dictionaries, I don't think it changed for all these years. There are multiple workarounds, two of them could be recommended.
First, change the internal data structure for one that is serializable. A list of pairs would do.
Second, use the DataContractSerializer rather than the xml serializer. The data contract serializer supports serialization of dictionaries.
See this thread
Serialize Class containing Dictionary member
You can use SerializableDictionary if you really want.
I want to serialize a MyClass, which is a class that contains a list MyClass.
In the XML, I want to write only myClass.Name, then when I deserialize it, I then find which MyClass should be in which other MyClass. I have the following code that properly serializes the list of MyClass into a list of string. However, it doesn't deserialize the list of string.
//List of actual object. It's what I use when I work with the object.
[XmlIgnore]
public List<TaskConfiguration> ChildTasks { get; set; }
//Used by the serializer to get the string list, and used
//by the serializer to deserialize the string list to.
[XmlArray("ChildTasks")]
public List<string> ChildTasksSurrogate
{
get
{
List<string> childTaskList = new List<string>();
if (ChildTasks != null)
childTaskList.AddRange(ChildTasks.Select(ct => ct.Name).ToList());
if (_childTasksSurrogate != null)
childTaskList.AddRange(_childTasksSurrogate);
//Clears it not to use it when it serializes.
_childTasksSurrogate = null;
return childTaskList;
}
set
{
_childTasksSurrogate = value;
}
}
[XmlIgnore]
private List<string> _childTasksSurrogate;
As I said, the serialization works. The problem lies with the deserialization. After the deserialization, MyClass._childTasksSurrogate is null.
The problem was related to HOW does the XmlSerializer deserializes the Xml :
I thought that the XmlSerializer would assign the whole property (read: myList = DeserializedList), while it looks like it adds all the elements (read: myList.AddRange(DeserializedList).
I've got a class which has been serialized into JSON, and which I'm trying to deserialize into an object.
e.g.
public class ContentItemViewModel
{
public string CssClass { get; set; }
public MyCustomClass PropertyB { get; set; }
}
the simple property (CssClass) will deserialize with:
var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);
But PropertyB gets an error...
We added a JavaScriptConverter:
ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});
But when we added 'MyCustomClass' as a 'SupportedType', the Deserialize method was never called. However when we have ContentItemViewModel as the SupportedType, then Deserialize is called.
We've got a current solution which looks something like this:
class ContentItemViewModelConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var cssClass = GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...
var propertyB= GetString(dictionary, "propertyB");
return new ContentItemViewModel{ CssClass = cssClass ,
PropertyB = new MyCustomClass(propertyB)}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new Exception("Only does the Deserialize");
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new List<Type>
{
typeof(ContentItemViewModel)
};
}
}
}
But we'd prefer a simpler solution of only deserializing MyCustomClass, as there are a number of other fields which are on the ViewModel, and it seems a waste to have to edit this converter every time we change/add a property....
Is there a way to Deserialize JUST PropertyB of type MyCustomClass?
Thanks for your help!
Have you considered using DatacontractJsonSerializer
[DataContract]
public class MyCustomClass
{
[DataMember]
public string foobar { get; set; }
}
[DataContract]
public class ContentItemViewModel
{
[DataMember]
public string CssClass { get; set; }
[DataMember]
public MyCustomClass PropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
ContentItemViewModel model = new ContentItemViewModel();
model.CssClass = "StackOver";
model.PropertyB = new MyCustomClass();
model.PropertyB.foobar = "Flow";
//Create a stream to serialize the object to.
MemoryStream ms = new MemoryStream();
// Serializer the User object to the stream.
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
ser.WriteObject(ms, model);
byte[] json = ms.ToArray();
ms.Close();
string s= Encoding.UTF8.GetString(json, 0, json.Length);
Console.ReadLine();
}
}
Add all possible classes to DatacontractJsonSerializer.KnownTypes if MyCustomClass has derivations.
For whatever it may be worth after all this time, but I stumbled over the same problem and the solution is that the Deserializer hasn't got a clue about the classes you are deserializing unless you give him the necessary information.
On the top level, it knows the type from the type parameter of Deserialize<>(). That's why your converter for ContentItemViewModel works. For nested objects, it needs __type properties and a JavaScriptTypeResolver.
var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
// set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);
A TypeResolver adds a __type property to each serialized object. You can write a custom type resolver that uses short names. In this sample, I use the SimpleTypeResolver from .net that "simply" stores the fully qualified type name as __type. When deserializing, the JavaScriptDeserializer finds __type and asks the TypeResolver for the correct type. Then it knows a type and can call a registered JavaScriptConverter.Deserialize method.
Without a TypeResolver, objects are deserialized to a Dictionary because JavaScriptSerializer doesn't have any type information.
If you can't provide a __type property in your json string, I think you'll need to deserialize to Dictionary first and then add a "guessing-step" that interprets the fields to find the right type. Then, you can use the ConvertToType method of JavaScriptSerializer to copy the dictionary into the object's fields and properties.
If you need to use the JavaScriptSerializer that is provides by ASP.NET and can't create your own, consider this section from the .ctor help of JavaScriptSerializer:
The instance of JavaScriptSerializer that is used by the asynchronous communication layer for invoking Web services from client script uses a special type resolver. This type resolver restricts the types that can be deserialized to those defined in the Web service’s method signature, or the ones that have the GenerateScriptTypeAttribute applied. You cannot modify this built-in type resolver programmatically.
Perhaps the GenerateScriptType Attribute can help you. But I don't know what kind of __type Properties are be needed here.
am new to Json so a little green.
I have a Rest Based Service that returns a json string;
{"treeNode":[{"id":"U-2905","pid":"R","userId":"2905"},
{"id":"U-2905","pid":"R","userId":"2905"}]}
I have been playing with the Json.net and trying to Deserialize the string into Objects etc.
I wrote an extention method to help.
public static T DeserializeFromJSON<T>(this Stream jsonStream, Type objectType)
{
T result;
using (StreamReader reader = new StreamReader(jsonStream))
{
JsonSerializer serializer = new JsonSerializer();
try
{
result = (T)serializer.Deserialize(reader, objectType);
}
catch (Exception e)
{
throw;
}
}
return result;
}
I was expecting an array of treeNode[] objects. But its seems that I can only deserialize correctly if treeNode[] property of another object.
public class treeNode
{
public string id { get; set; }
public string pid { get; set; }
public string userId { get; set; }
}
I there a way to to just get an straight array from the deserialization ?
Cheers
You could use an anonymous class:
T DeserializeJson<T>(string s, T templateObj) {
return JsonConvert.Deserialize<T>(s);
}
and then in your code:
return DeserializeJson(jsonString, new { treeNode = new MyObject[0] }).treeNode;
Unfortunately JSON does not support Type Information while serializing, its pure Object Dictionary rather then full Class Data. You will have to write some sort of extension to extend behaviour of JSON serializer and deserializer in order to support proper type marshelling.
Giving root type will map the object graph correctly if the types expected are exact and not derived types.
For example if I have property as array of base class and my real value can contain derived child classes of any type. JSON does not support it completely but web service (SOAP) allows you to serialize objects with dynamic typing.