Click here to Skip to main content
15,887,676 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello
i am working on a C# web application in which i have to save and restore the state of the application, i am doing this by serialization and deserialization. every thing works fine but the problem is when i deserialize list<object> in which the object has a property from other class , then their reference seems to be broken, only the value is shown but no connection rests
let me show some parts of the code related to the subject:

C#
[DataContract (IsReference = true)]
class course:faculty
{

     [DataMember]
     private string CourseName;


     public string getname
     {
     get{return CourseName;}
     set{CourseName=value;}
     }
    .
    .
    .
    [DataMember]
    private prof professor;

    public prof Prof               // prof is the object from prof class
    {
        get { return professor; }
        set { professor = value; }
    }  

}


[DataContract(IsReference = true)]
class prof:faculty
{


 [DataMember]
    private List<course> teaching = new List<course>();    // course is the object of the course class

       public List<course> Teaching { get { return teaching; } set { teaching = value; } }
    

}

[DataContract(IsReference = true)]
class level:faculty
{

    [DataMember]
    private List<course> conflicts = new List<course>();   //conflicts is the list of objects from courses class
 
    public List<course> Conflicts { get { return conflicts; } }


}



[DataContract(IsReference = true)]
class faculty:departman
{
.
.

}

[DataContract(IsReference = true)]
class departman
{
.
.
}



i have three list<>

XML
static List<course> Courses = new List<course>();
static List<level> Levels = new List<level>();
static List<prof> Profs = new List<prof>();


i serialize these and save to DB, and then deserialize back to list<> later

now if i access to one the level objects, lets say L1 and change one of its conflicts property from another class, lets say L1.Conflicts.Prof

now the prop value will be change in the levels list but this change never affected to the course list itself on the course.prof property,i think that what is getting from deserialize is the value without the link to the base class


these are all working properly before serialize and deserialize , means if i change course.prof in in an object the value will be assigned to the level.course.prof as well and vise versa

i have used three different methods for serialize and deserialize
both three binary formatter , Protobuf, Json.net (newtonsoft) , all of them acts the same

hope i was clear enough, i am really confused , any help would be appreciated
thanks in advance
Posted
Updated 11-Aug-15 6:27am
v3
Comments
Sergey Alexandrovich Kryukov 11-Aug-15 12:08pm    
Could you show this "other class"? Does it have the attribute [DataContract]? Does it have members marked with [DataMember]?
Another question, just in case: is your data structure a tree (that is, are there are cycles in reference graph)? JSON data contract serializer does not support it, but DataContractSerialize does.
—SA
Saeed Jafarian 11-Aug-15 12:24pm    
there is no other class further , i had shown what i mean by other class : like prof class , like course class. and yes it has cycle, the prof has course and course has prof then yes, it has cycle but i used protobuf or binary formatter and yet this problem exist. what about that?
Sergey Alexandrovich Kryukov 11-Aug-15 12:37pm    
Thank you for the clarification.
Use:
[DataMember]
prof Professor { get; set; }
I'm not saying it's to solve the problem, it's to say that having explicit backup field is pointless. Another approach is to avoid null:

[DataMember]
prof professor = new prof();

public prof Professor { get professor; }

—SA
Saeed Jafarian 11-Aug-15 13:14pm    
thank you for your contribution,yes, you are right
Saeed Jafarian 11-Aug-15 12:26pm    
i used newtonsoft json.net which support cycles

1 solution

Saeed Jafarian wrote:

so if i use DataContractSerializer the problem should be solved, i don`t have problem with switching, i have tried 3 types of serializer up to now.
i will try and make you know if this works
If you do it, the problem will be sorted by using this: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.preserveobjectreferences(v=vs.110).aspx[^].

See also: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer%28v=vs.110%29.aspx[^].

If you assign PreserveObjectReferences to true, all [DataMember] objects which can be cross-referenced will be given a unique attribute (unfortunately, all of them, redundantly; there is no a way to opt out any of then). When some other object's property references the object again, the reference to the already serialized object will be added (another attribute), instead of serializing it again (which otherwise would case "infinite" recursion). On deserialization, all those references will be resolved automatically.

I think that it does not happen with JSON just because JSON does not have standard provisions for such things: there are no certain things usual for XML, such as comments, namespaces, etc. At the same time, JSON is more logical and simple, there are no controversies in standard definitions XML suffers from. But cross-references makes using of JSON quite problematic.

—SA
 
Share this answer
 
Comments
Saeed Jafarian 12-Aug-15 7:43am    
Hello again
i did serialize and deserialize with dataContractSerializer but the problem still exists,
what i have done:

<pre lang="cs">
XmlDocument SerialedCourse = new XmlDocument();
DataContractSerializer CourseSerializer = new DataContractSerializer(typeof(List <'course'> ), null, int.MaxValue, false, true /* preserveObjectReferences */, null);

using (MemoryStream courseStream = new MemoryStream())
{
CourseSerializer.WriteObject(courseStream, Courses);
courseStream.Position = 0;
SerialedCourse.Load(courseStream);

}
</pre>
and then insert it into the sql table with xml column, i checked the result and i think the refrencing exist beacause i see something like <professor z:Id="9"> in the course array list, but i dont know why after deserialization that problem not solved,
for deserialization i used something like:

string temp = dt_load.Rows[0][1].ToString();


byte[] byteArray = Encoding.UTF8.GetBytes(dt_load.Rows[0][1].ToString());

MemoryStream courseStream = new MemoryStream(byteArray);
DataContractSerializer CourseSerializer = new DataContractSerializer(typeof(List <'course'> ));

Courses = (List<'course'>)CourseSerializer.ReadObject(courseStream);


i am totally confused
Sergey Alexandrovich Kryukov 12-Aug-15 10:26am    
I can see a lot of irrelevant code. I can see your "output of serialization", which is not even XML. I don't understand what you are doing. You need to do just one thing: serialize and then deserialize. Or the round trip: serialize (preserve file1), deserialize, get new object graph, serialize new object graph as file2, compare file1 and file2. Forget Encoding, database, etc. Serialization is the way to preserve object graph in a stream and later restore the object graph in memory as it was before.
—SA
Saeed Jafarian 12-Aug-15 11:07am    
ok now i do it with fileStream
serializing:

DataContractSerializer CourseSerializer = new DataContractSerializer(typeof(List<'course'>), null, int.MaxValue, false, true /* preserveObjectReferences */, null);
XmlDictionaryWriter writer = null;
FileStream fs = null;
fs = new FileStream(Server.MapPath("course.xml"), FileMode.Create);
writer = XmlDictionaryWriter.CreateTextWriter(fs);
CourseSerializer.WriteObject(writer, Courses);
writer.Close();
fs.Close();


deserializing:

FileStream fs = null;
DataContractSerializer ser = null;
XmlDictionaryReader reader = null;
fs = new FileStream(Server.MapPath("course.xml"), FileMode.OpenOrCreate);
reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
ser = new DataContractSerializer(typeof(List<course>));
Courses = (List<'course'>)ser.ReadObject(reader);
fs.Close();
reader.Close();

and do it for level and prof list either

no database, no encoding, just stream, but the problem not solved....
Sergey Alexandrovich Kryukov 12-Aug-15 11:21am    
Still, a lot of redundant code. Did you get two files?
You don't need XmlDictionaryReader, MapPath, and a lot more.
Okay, can you create a simple model:
Parent
---List-of-children
-----child1
-----child2
---List-of-referencing-children
------someObject
---------referenceToChild2
------someObject
...

Serialize and deserialize it, to see how technology works...
—SA
Saeed Jafarian 12-Aug-15 11:26am    
no i get just one file for course list<>.
the point is i am deserializing the xml to the list without problem, even with the database and encoding i could deserialize. but the reference is broken between object.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900