locked
How to Serialize a non Sertilizable object into Binary? RRS feed

  • Question

  • Hi ,
     
    I have an object ObjXML of type XmlDocument (object may be of any non serializable class). I have to Serialize it into Binary. I know that XmlDocument does not implement ISerializeable.  That's why according to framework we cannot serialize it. 
    So is there anyway around to get this object (ObjXML) into Binary.
     
    I will be highly obliged to your help. 
     
    Regards
    Muhammad Waqas Bashir
    Wednesday, August 10, 2005 7:46 AM

Answers

  • That wouldn't be possible using serialization surrogates since you have to associate the surrogate with a type. Default serialization does, however, serialize all public and private fields so you could use reflection to get fields of an object.

    You really should be careful about serializing non-serializable objects, though. For some objects it's fine, but for other objects - like Windows Forms controls - you typically shouldn't. In the case of controls, they are tied to a Window handle that is valid only for your machine and only for that instance of your application. Attempting to deserialize the control on another machine or for another run of your application could simply fail or have disasterous results.
    Thursday, August 11, 2005 1:13 PM

All replies

  • You can implement ISerializationSurrogate to either serialize non-serializable objects, or override serialization for classes you either can't extend or don't want to. You then add this surrogate to an ISurrogateSelector - for which SurrogateSelector in the BCL is a default implementation - and pass this to your formatter. An example is given below. Compile this, run it, and - if you'd like - open Example.bin to see your document serialized using a BinaryFormatter.


    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Xml;

    class SerializeXmlDocument
    {
     static void Main()
     {
      // Create an XmlDocument to serialize.
      XmlDocument doc = new XmlDocument();
      doc.LoadXml(@"
    <root>
     <branch>
      <leaf>First leaf</leaf>
      <leaf>Second leaf</leaf>
     </branch>
     <branch>
      <leaf>Third leaf</leaf>
     </branch>
    </root>");

      // Pack it into our example serializable object.
      Tree tree = new Tree("Example", doc);

      // Create a serialization surrogate to serialize the XmlDocument.
      XmlDocumentSerializer docSerializer = new XmlDocumentSerializer("doc");

      // Create the surrogate selector.
      SurrogateSelector selector = new SurrogateSelector();
      selector.AddSurrogate(typeof(XmlDocument), new StreamingContext(StreamingContextStates.All),
       docSerializer);

      // Now serialize the object to a binary file.
      using (FileStream file = File.Create("Example.bin"))
      {
       BinaryFormatter formatter = new BinaryFormatter(selector,
        new StreamingContext(StreamingContextStates.File));
       formatter.Serialize(file, tree);
      }
     }
    }

    [Serializable]
    class Tree
    {
     string name;
     XmlDocument doc;

     internal Tree(string name, XmlDocument doc)
     {
      this.name = name;
      this.doc = doc;
     }

     public string Name { get { return name; } }
     public XmlDocument Document { get { return doc; } }
    }

    class XmlDocumentSerializer : ISerializationSurrogate
    {
     string name;
     
     // Prevent default instantiation.
     XmlDocumentSerializer() {}

     internal XmlDocumentSerializer(string name)
     {
      if (name == null)
       throw new ArgumentNullException("name");

      this.name = name;
     }
     
     public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
     {
      XmlDocument doc = obj as XmlDocument;
      if (doc != null)
      {
       using (StringWriter writer = new StringWriter())
       {
        doc.Save(writer);

        // Save the string to the SerializationInfo.
        info.AddValue(name, writer.ToString());
       }
      }
     }

     public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
     {
      string xml = info.GetString(name);
      if (xml != null)
      {
       XmlDocument doc = new XmlDocument();
       doc.LoadXml(xml);
       return doc;
      }

      return null;
     }
    }

     

    Wednesday, August 10, 2005 4:28 PM
  • Thankyou very much for your prompt reply. Your Code is perfect for XMLDocument serialization. But can you please send me generic sample code for the serializaiton of any object who does not implement iserialization.

    For example:-

    Dim arr1 As Byte() = Nothing

    if obj.isSerializable = false then
        arr1 = CustomSerializer(obj)
    end if



    function CustomSerializer(obj) as binary()

    // How to implement it....



    end function
    Thursday, August 11, 2005 3:38 AM
  • That wouldn't be possible using serialization surrogates since you have to associate the surrogate with a type. Default serialization does, however, serialize all public and private fields so you could use reflection to get fields of an object.

    You really should be careful about serializing non-serializable objects, though. For some objects it's fine, but for other objects - like Windows Forms controls - you typically shouldn't. In the case of controls, they are tied to a Window handle that is valid only for your machine and only for that instance of your application. Attempting to deserialize the control on another machine or for another run of your application could simply fail or have disasterous results.
    Thursday, August 11, 2005 1:13 PM
  • Thankyou very much you solved my problem.

    Regards,
    Muhammad
    Monday, August 15, 2005 12:45 AM
  • Hi!
    I need to serialize XmlDocument to send it using remoting over tcp/binary channel. I created new class that inherts XmlDocuments and implements ISerialization and it seems to work just fine, but as I'm pretty new to this topic I'm not sure if that does something it shouldn't because the code just seems too simple...
    Anyway, here's the code:



    using System;
    using System.Xml;
    using System.Runtime.Serialization
    public class MyXmlDocument:XmlDocument,ISerializable
    {
       public MyXmlDocument():base(){}

       protected MyXmlDocument(SerializationInfo info, StreamingContext context)
       {
          this.LoadXml(info.GetString("xmlDocument");
       }

       public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
       {
          info.AddValue("xmlDocument", this.OuterXml, typeof(string));
       }
    }

     


    Please comment this solution if you know a better way to do this job...
    Is there any way to send the whole XmlDocument object byte by byte using the same channel?

    Thank you very much!
    Tuesday, September 6, 2005 12:08 PM
  • The following uses a MemoryStream (just another way of doing it)

     

    [Serializable()]

    public class CustomData : XmlDocument, ISerializable

    {

     

    public CustomData(XmlDocument xmlDoc)

    {

    SetXmlDoc(xmlDoc);

    }

    public CustomData()

    {

    SetXmlDoc(null);

    }

    protected CustomData(SerializationInfo info, StreamingContext context)

    {

    XmlDocument xmlDoc = null;

     

    MemoryStream stream = (MemoryStream)info.GetValue("MemoryStreamDoc", typeof(MemoryStream));

    stream.Seek(0, SeekOrigin.Begin);

     

    if (stream != null && stream.Length > 0)

    {

    xmlDoc = new XmlDocument();

    xmlDoc.Load(stream);

    }

     

    SetXmlDoc(xmlDoc);

    }

     

    private void SetXmlDoc(XmlDocument xmlDoc)

    {

    if (xmlDoc != null && xmlDoc.DocumentElement != null)

    this.AppendChild(this.ImportNode(xmlDoc.DocumentElement, true));

    else

    this.AppendChild(this.CreateElement("CustomData"));

    }

     

    public void GetObjectData(SerializationInfo info, StreamingContext context)

    {

    MemoryStream stream = new MemoryStream();

    Save(stream);

    info.AddValue("MemoryStreamDoc", stream);

    }

    }
    Wednesday, February 6, 2008 10:30 PM