Share via


serialize and deserialize c# class into string

Question

Tuesday, June 21, 2011 8:58 AM

Hello

im trying to serialize and deserialize c# class into a string.

i read a lot of posts, but still im unable to solve my problem and would apprciate any input.

im using 

/serialize

  MemoryStream ms = new MemoryStream();
 BinaryFormatter bf = new BinaryFormatter();
  bf.Serialize(ms, data); /// data is the class i wanna serialize.
   ms.Seek(0, 0);
   StreamReader rdr = new StreamReader(ms);
   string str = rdr.ReadToEnd();
    byte[] byteArray = Encoding.ASCII.GetBytes(str);

//deserialize

  MemoryStream stream = new MemoryStream(byteArray);

 stream.Seek(0, 0);

 BinaryFormatter bf = new BinaryFormatter();
  object d = bf.Deserialize(stream);

when im using this code on simple classes it works just fine, but i when i try to use on the actual class i need to serialize i get runtime error

-> Object of type 'chronoswars.MasterUnit' cannot be converted to type 'chronoswars.UnitBoardData'.

im not sure why the compiler is trying to convert this classes it doesnt make any sense to me.

when im  serializing and deserializing the very same class from a file it works just fine. so it is possible for example to get the string from the file, however using a file just to do so is not a solution for me.

i have no idea why im getting this error and or how solve it, or go around it.

Thanks

All replies (19)

Wednesday, June 22, 2011 4:52 AM ✅Answered

Found the problem, you are writing the string to a new stream and encoding it. instead of just returning the buffer. Here is an example for you that i cleaned up a bit with using-blocks to closed the streams. and here you can specify the types to use in the methods:

class Program
{
   static void Main(string[] args)
   {
      var sc = new Someclass();
      var b = ToString(sc);

      try
      {
         var o = FromString<Someclass>(b);
         Console.WriteLine(o.listi.Count);
      }
      catch (SerializationException e)
      {
         Console.WriteLine(e.Message);
      }
      Console.ReadLine();
   }

   [Serializable]
   public class Someclass
   {
      public List<int?> listi;
      public Someclass()
      {
         listi = new List<int?>();
         for (int x = 0; x < 100; x++)
            listi.Add(x);
      }
   }

   public static TType FromString<TType>(byte[] byteArray)
   {
      using (var stream = new MemoryStream(byteArray))
      {
         var bf = new BinaryFormatter();
         return (TType)bf.Deserialize(stream);
      }
   }

   public static byte[] ToString<TType>(TType data)
   {
      using (var ms = new MemoryStream())
      {
         var bf = new BinaryFormatter();
         bf.Serialize(ms, data);
         return ms.GetBuffer();
      }
   }
}

Wednesday, June 22, 2011 7:16 AM ✅Answered

I think if you use these two methods instead you are using the ASCII encoding on both the serialize AND deserialize methods it should work

   public static TType FromString<TType>(string input) 
   { 
      var byteArray = Encoding.ASCII.GetBytes(input);
      using (var stream = new MemoryStream(byteArray)) 
      { 
         var bf = new BinaryFormatter(); 
         return (TType)bf.Deserialize(stream); 
      } 
   } 
 
   public static string ToString<TType>(TType data) 
   { 
      using (var ms = new MemoryStream()) 
      { 
         var bf = new BinaryFormatter(); 
         bf.Serialize(ms, data); 
         return Encoding.ASCII.GetString(ms.GetBuffer()); 
      } 
   } 

Wednesday, June 22, 2011 7:38 AM ✅Answered

Yes!!!! i cant belive this, its actually working!!!

one thing thouogh right before u wrote this last post i was trying to do about the same.

anyway final result -  if u use ASCII encoding, for some reason some of the list items get trunced out.

if i changed from ascii to unicode (ovcourse on both ends) it works just fine!

Thank you very much for your help, u did my day!!!


Tuesday, June 21, 2011 9:04 AM

How do you call these methods? You need to cast, so how do you do that?


Tuesday, June 21, 2011 9:07 AM

lets say i have a class MytypeClass ;

MytypeClass newdata = (MytypeClass )bf.Deserialize(stream);

thats how i cast, regardless i get the runtime error before that when im trying to deserialize.

thanks again!

Tuesday, June 21, 2011 9:13 AM

And the stream you pass into the method, where does that come from? A file? could it be an old serialized file of some other class?


Tuesday, June 21, 2011 9:22 AM

no, im wanna build the stream from the string, but for time being im buliding the memory stream from byte array (byte[]),

which is built from the string

str - is the string im wanna deserialize

   byte[] byteArray = Encoding.ASCII.GetBytes(str);

  MemoryStream stream = new MemoryStream(byteArray);

Tuesday, June 21, 2011 9:24 AM

Wait, what does the string contain?

You know that the string must contain a serialized object of exactly the same typ as the one you are trying to cast to right?


Tuesday, June 21, 2011 9:30 AM

this is to code to serialize and then deserialzie, like i said it works fine on simle clases, but i get the runtime error  on a much more complex class.

same class can and is being serialized into a file. i waana do the smae only without using the file

 MemoryStream ms = new MemoryStream();
 BinaryFormatter bf = new BinaryFormatter();
  bf.Serialize(ms, data); /// data is the class i wanna serialize.
   ms.Seek(0, 0);
   StreamReader rdr = new StreamReader(ms);
   string str = rdr.ReadToEnd();
    byte[] byteArray = Encoding.ASCII.GetBytes(str);

//deserialize

  MemoryStream stream = new MemoryStream(byteArray);

 stream.Seek(0, 0);

 BinaryFormatter bf = new BinaryFormatter();
  object d = bf.Deserialize(stream);

thx again

Tuesday, June 21, 2011 9:35 AM

Its impossible to say without seeing more code.

When you deserialize a string, that does not contain the same type as you are trying to cast to.

If you are running this in visual studio you could debug and what what the object that comes out of the Deserialize method really contains. If it is the type you think it is. 


Tuesday, June 21, 2011 9:42 AM

yes i understand that, the class im trying to serialize is a very complex class and its impossible to share it here.

i get the runtime error on this

object d = bf.Deserialize(stream); when trying to deserialize.

is there a diffrent approch on how to serialize an object into a string?

Again thanks for your help

Tuesday, June 21, 2011 10:56 AM

ok, i started to try to seralize class by class of the main class im trying to serialize and i found the problem.

  some class contains a list of element of a class. when i add more then 16~ objects to that class the deserializations fails.

further more when i created just some class with an int list with in, when i load to that list more than 90~ ints im 

getting the exact same error!

any ideas?

the entire code:

// to unserialize an object from byte array

    public object FromString(byte[] byteArray)
        {
            
            MemoryStream stream = new MemoryStream(byteArray);
    
            BinaryFormatter bf = new BinaryFormatter();

            object d = null;
            try
            {
                    d = bf.Deserialize(stream);
            }
            catch (Exception e)
            {
                
                
            }
             

          
           
            return d;
        }

// to seriazlie an object into byte array
        public byte[] tostring(object data)
        {
            MemoryStream ms = new MemoryStream();

            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, data);
            ms.Seek(0, 0);
            StreamReader rdr = new StreamReader(ms);
            string str = rdr.ReadToEnd();
         
            byte[] byteArray = Encoding.ASCII.GetBytes(str);
            
            return byteArray ;
        }

//just some class to serialize

 public class MasterunitCollectiondemo
    {
    
        public List<int> listi;

   public MasterunitCollectiondemo()
        {

          listi = new List<int>();

for (int y=0;y<100;y++){
                listi.Add(y);}

}

}

// code that generate runtime error

 MasterunitCollectiondemo md = new MasterunitCollectiondemo();

            byte[] b = tostring(md);
       
            object o = FromString(b) ; -> here i get an error if the list in md is bigger than about 90!!!

thanks for your help

Wednesday, June 22, 2011 12:44 AM

Exacly what errormessage do you get there?


Wednesday, June 22, 2011 3:48 AM

when i insert for example 100 ints, i get SerializationException

Binary stream '63' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.


Wednesday, June 22, 2011 4:14 AM

You are not sending the same code now right? That example wont even work since the Masterdemo class dont have the Serializable attribute


Wednesday, June 22, 2011 4:22 AM

thank you very much for your help, i appreciate it very much!

you are most right,  i only created this code to show an example(and i wrote in this post), and yes its missing serialize and initialize of the list.

i created a new project and tested it and im getting the same error .

this is the real complied code:(so u can test it yourself)

    [Serializable]
    public class Someclass
    {
        private List<int> listi;
        public Someclass()
        {
            listi = new List<int>();
            for (int x = 0; x < 100; x++)
                listi.Add(x);
        }           
    }

    public object FromString(byte[] byteArray)
        {

            
          

            MemoryStream stream = new MemoryStream(byteArray);
    
          //  stream.Seek(0, 0);
            BinaryFormatter bf = new BinaryFormatter();
            

            object d = null;
            try
            {
                    d = bf.Deserialize(stream);
            }
            catch (ArgumentException  e)
            {
                
                
            }
             

          
           
            return d;
        }

        public byte[] tostring(object data)
        {
            MemoryStream ms = new MemoryStream();

            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, data);
            ms.Seek(0, 0);
            StreamReader rdr = new StreamReader(ms);
            string str = rdr.ReadToEnd();

        
            byte[] byteArray = Encoding.ASCII.GetBytes(str);
            
            return byteArray ;
        }

public void checkserialize ()

{

  Someclass sc = new Someclass();

            byte[] b = tostring(sc);

   try
            {

                object o = FromString(b);// <=====error here!!!

               

}

 catch (SerializationException   e)
            {
                

                
            }

       

}

Wednesday, June 22, 2011 7:12 AM

Thank you very much help!

i spent hrs trying to solve this, i tried so many things u wouldnt belive it....

anyway one last question thouogh, the entire purpess of this is to be able to save SomeClass (from the above example) into a string,

so that i will be able to save it a sql database table.

your code works great, but im not sure how to cast the bytearray into a string without losing chars and vice verca.

Again many thanks for your help! you were truly helpfull!


Wednesday, June 22, 2011 7:52 AM

Great, glad i could help :)


Monday, July 11, 2011 2:15 AM

Hi,

I don't mean to hijack the post but I am encountered with a somewhat related problem and I was hoping you could help me figure out where I made an error.

I have a serializable class called Measurement. I also used your code to help me with the customized serialization/deserialization. I am using RabbitMQ to write and read messages (of Measurement objects). I am getting the following error on the command line to the left. It looks the error originates from the deserialize method?

Unhandled Exception: System.InvalidCastException: Unable to cast object of 'Measurement' to type 'Measurement' .

I have also included the entire code for reference.

Thanks in advance,

//MB1.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

//start alternate serialization
public static class AltSerialization
{
    public static byte[] AltSerialize(Measurement m)
    {
     using (var ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, m);
            return ms.GetBuffer();
        }
    }

    public static Measurement AltDeSerialize(byte[] seriM)    
    {
    using (var stream = new MemoryStream( seriM ))
        {
            BinaryFormatter bf = new BinaryFormatter();
            return (Measurement)bf.Deserialize(stream);
        }
    } 
}
//end alternte serialization

[Serializable()] //This attribute sets class to be serialized
public class Measurement : ISerializable
{            
    [NonSerialized] public int id;
    public int time; //timestamp
    public double value;
    
    public Measurement()
    {
        id = 1;
        time = 12;
        value = 0.01;
    }
    
    public Measurement(int _id, int _time, double _value)
    {
        id = _id;
        time = _time;
        value = _value;
    }
    
    //Deserialization constructor   
    public Measurement(SerializationInfo info, StreamingContext ctxt)
    {
        //Assign the values from info to the approporiate properties                        
        //time = (int)info.GetValue("MeasurementTime", typeof(int));
        //value = (double)info.GetValue("MeasurementValue", typeof(double));
    }
        
    //Serialization function    
    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
        // Custom name-value pair
        // Values must be read with the same name they're written       
        //info.AddValue("MeasurementTime", time);
        //info.AddValue("MeasurementValue", value);
    }
}

public interface IMessageBus
{    
    string MsgSys       // Property 1
    {
        get;
        set;
    }

    void write (Measurement m1);
    Measurement read();
    void publish(string queue);   
    void subscribe(string queue);   
}

public class Rabbit : IMessageBus
{   
    // Implementation of methods for Rabbit class go here
    private List<string> publishQ = new List<string>();
    private List<string> subscribeQ = new List<string>();
    
  
    public void write ( Measurement m1 )
    {
        ConnectionFactory factory = new ConnectionFactory();
        factory.HostName = "localhost";
        using (IConnection connection = factory.CreateConnection())
        using (IModel channel = connection.CreateModel()) {
            
            channel.ExchangeDeclare("myExchange", "direct");
            
            byte[] body = AltSerialization.AltSerialize( m1 );
            
            foreach (string queue in publishQ) 
            {
                channel.BasicPublish("myExchange", queue, null, body);
                Console.WriteLine("\n [x] Message sent to queue {0}.", queue );
            }
        }
    }
    
    public void publish(string queueName)
    {
        publishQ.Add(queueName);
    }
    
    public Measurement read() 
    {
        ConnectionFactory factory = new ConnectionFactory();
        factory.HostName = "localhost";
        using (IConnection connection = factory.CreateConnection())
        using (IModel channel = connection.CreateModel()) {

            channel.ExchangeDeclare("myExchange", "direct");
            string queue_name = channel.QueueDeclare();

            foreach (string severity in subscribeQ) {
                channel.QueueBind(queue_name, "myExchange", severity);
            }

            Console.WriteLine(" [*] Waiting for messages. " +
                              "To exit press CTRL+C");

            QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
            channel.BasicConsume(queue_name, true, consumer);

            while(true) {
                BasicDeliverEventArgs ea =
                    (BasicDeliverEventArgs)consumer.Queue.Dequeue();
    
                Console.WriteLine(" [x] Received ");
                return AltSerialization.AltDeSerialize( ea.Body );
           }
        }
    }
    
    public void subscribe(string queueName)
    {
        subscribeQ.Add(queueName);
    }
    
    public static string MsgSysName;
    public string MsgSys
    {
        get 
        { 
            return MsgSysName;
        }
        set
        {
            MsgSysName = value;
        }
    }
    
    public Rabbit(string _msgSys) //Constructor
    {
        System.Console.WriteLine("\nMsgSys: RabbitMQ");
        MsgSys = _msgSys;
    }
}

public class Zmq : IMessageBus
{
    public void write ( Measurement m1 )
    {
        //
    }
    public Measurement read() 
    {
        //
        return null;
    }
    public void publish(string queue)
    {
    //
    }
    public void subscribe(string queue)
    {
    //      
    }   
    
    public static string MsgSysName;
    public string MsgSys
    {
        get 
        { 
            return MsgSysName;
        }
        set
        {
            MsgSysName = value;
        }
    }
    
    // Implementation of methods for Zmq class go here
    public Zmq(string _msgSys) //Constructor
    {
        System.Console.WriteLine("ZMQ");
        MsgSys = _msgSys;
    }
} 

public class MessageBusFactory
{
    public static IMessageBus GetMessageBus(string MsgSysName)
    {
        switch ( MsgSysName )
        {
            case "Zmq":
                return new Zmq(MsgSysName);
            case "Rabbit":
                return new Rabbit(MsgSysName);
            default:
                throw new ArgumentException("Messaging type " +
                    MsgSysName + " not supported." );
        }
    }
}

public class MainClass
{
    public static void Main()
    {
        //Asks for the message system
        System.Console.WriteLine("Enter name of messageing system: ");
        System.Console.WriteLine("Usage: [Rabbit] [Zmq]");
        string MsgSysName = (System.Console.ReadLine()).ToString();
        
        //Create a new Measurement message
        Measurement m1 = new Measurement(2, 2345, 23.456);
        
        //Declare an IMessageBus instance:
        //Here, an object of the corresponding Message System
            // (ex. Rabbit, Zmq, etc) is instantiated
        IMessageBus obj1 = MessageBusFactory.GetMessageBus(MsgSysName);
                    
        System.Console.WriteLine("\nA {0} object is now created.", MsgSysName);
     
        //System.Console.WriteLine("Test message:\nID: {0}", m1.id);
        //System.Console.WriteLine("Time: {0}", m1.time);
        //System.Console.WriteLine("Value: {0}", m1.value);
                
        // Ask queue name and store it
        //System.Console.WriteLine("Enter a queue name: ");
        //string QueueName = (System.Console.ReadLine()).ToString();
        //obj1.publish( QueueName );
        
        //System.Console.WriteLine("Enter another queue name: ");
        //QueueName = (System.Console.ReadLine()).ToString();
        //obj1.publish( QueueName );
        
        // Write message to the queue
        //obj1.write( m1 ); 
                
        System.Console.WriteLine("Enter a queue to subscribe to: ");
        string QueueName = (System.Console.ReadLine()).ToString();
        obj1.subscribe( QueueName );
            
        // Read message from the queue
        Measurement m2 = new Measurement(); 
        m2 = obj1.read();
    }
}