Demi
Demi

Reputation: 328

DeSerialization gives weird runtime error?

De-serialization not working. It gives me the following run-time error:

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

I really can't see what is wrong with it.

//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    
        Console.WriteLine("DeSerialization construtor called.");
        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);
    }
}


//AFTER THIS, IS FOR TEST FILES app1.cs, app2.cs, and the reference refer.cs.

//app1.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using refer;
using System.Reflection;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
[assembly: AssemblyVersion("1.0.0.0")]



public class MainClass
{
    public static void Main()
    {
        //Create a new Measurement message
        Measurement m1 = new Measurement(2, 2345, 23.456);
        System.Console.WriteLine("\nm1.id = {0}", m1.id);
        System.Console.WriteLine("m1.time = {0}", m1.time);
        System.Console.WriteLine("m1.value = {0}", m1.value);

        /*byte[] bArray = AltSerialization.AltSerialize( m1 );
        Measurement m2 = new Measurement();
        m2 = AltSerialization.AltDeSerialize(bArray);
        System.Console.WriteLine("\nm2.id = {0}", m2.id);
        System.Console.WriteLine("m2.time = {0}", m2.time);
        System.Console.WriteLine("m2.value = {0}", m2.value);*/

        ConnectionFactory factory = new ConnectionFactory();
        factory.HostName = "localhost";
        using (IConnection connection = factory.CreateConnection())
        using (IModel channel = connection.CreateModel())
        {
            channel.QueueDeclare("hello", true, false, false, null);

            byte[] body = refer.AltSerialization.AltSerialize( m1 );

            channel.BasicPublish("", "hello", null, body);
            Console.WriteLine(" [x] Sent ");
        }
    }
}


//app2.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using refer;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]



public class MainClass
{
    public static void Main()
    {

        /*/Create a new Measurement message
        Measurement m1 = new Measurement(2, 2345, 23.456);
        System.Console.WriteLine("\nm1.id = {0}", m1.id);
        System.Console.WriteLine("m1.time = {0}", m1.time);
        System.Console.WriteLine("m1.value = {0}", m1.value);

        byte[] bArray = AltSerialization.AltSerialize( m1 );*/

        Measurement m2 = new Measurement();

        ConnectionFactory factory = new ConnectionFactory();
        factory.HostName = "localhost";
        using (IConnection connection = factory.CreateConnection())
        using (IModel channel = connection.CreateModel()) {
            channel.QueueDeclare("hello", false, false, false, null);

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

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

                BasicDeliverEventArgs ea =
                    (BasicDeliverEventArgs)consumer.Queue.Dequeue();

                m2 = refer.AltSerialization.AltDeSerialize(ea.Body); 

                System.Console.WriteLine(" \n[x] Received ");
                System.Console.WriteLine("\nm2.id = {0}", m2.id);
                System.Console.WriteLine("m2.time = {0}", m2.time);
                System.Console.WriteLine("m2.value = {0}", m2.value);
        }
    }
}

//refer.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]

namespace refer
{
    //start alternate serialization
    public static class AltSerialization
    {
        public static byte[] AltSerialize(Measurement m)
        {
         using (var ms = new MemoryStream())
            {
                var bf = new BinaryFormatter();
                bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
                bf.Serialize(ms, m);
                return ms.GetBuffer();
            }
        }

        public static Measurement AltDeSerialize(byte[] seriM)    
        {
        using (var stream = new MemoryStream( seriM ))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
                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    
            Console.WriteLine("DeSerialization construtor called.");
            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 class MainClass
{
    public static void Main() 
    {

    }
}

Upvotes: 0

Views: 669

Answers (5)

agent-j
agent-j

Reputation: 27943

Edit:

The assembly names of the console applications are different, so even if the namespace and type names are the same, the BinaryFormatter still records the name of the assembly. Define the Measurement class in a common class library assembly and reference it from both console apps.

Original answer:

Most likely, the side that serialized the object was compiled with a different version of the Assembly than the side that deserialized it. Check in the AssemblyInfo.cs file for the assembly containing Measurement to make sure that the AssemblyVersion is fully specified.

[assembly: AssemblyVersion("1.0.0.0")]

not

[assembly: AssemblyVersion("1.0.*")]

If that doesn't work, make sure that assembly file is identical in both places.

Upvotes: 2

platon
platon

Reputation: 5340

One more solution, which might help you. Set the BinaryFormatter's AssemblyFormat property to Simple value in both serialization and deserialization methods:

bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;

Does this help?

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1063884

Since (comments) you expressed an interest in avoiding this scenario, here's how I would do it:

using System.IO;
using ProtoBuf;
public static class AltSerialization
{
    public static byte[] AltSerialize(Measurement m)
    {
        using (var ms = new MemoryStream())
        {
            Serializer.Serialize(ms, m);
            return ms.ToArray();
        }
    }

    public static Measurement AltDeSerialize(byte[] seriM)
    {
        using (var stream = new MemoryStream(seriM))
        {
            return Serializer.Deserialize<Measurement>(stream);
        }
    }
}

[ProtoContract]
public class Measurement
{
    public int id; // not serialized
    [ProtoMember(1)]
    public int time; // serialized as field 1
    [ProtoMember(2)]
    public double value; // serialized as field 2

    public Measurement()
    {
        id = 1;
        time = 12;
        value = 0.01;
    }

    public Measurement(int _id, int _time, double _value)
    {
        id = _id;
        time = _time;
        value = _value;
    }
}

well, except I wouldn't have public fields ;p If you don't want the attributes, they can be avoided too, in a number of ways that I can explain if you really want.

Advantages:

  • faster and smaller
  • not tied to any platform (you could load that in a C++/java/etc protobuf client very easily)
  • not tied to any particular type or field names
  • no risk of accidentally serializing extra objects through event subscriptions etc
  • most common serialization concepts fully supported

Upvotes: 0

Tigran
Tigran

Reputation: 62265

Just trying to guess: you're trying to deserialize binaries with Measurement class which is now in different namespace then in the moment of serialization of that file.

Check the code that previously serialized your data and check that Measurement namepsace in regard of yours.

Regards.

Upvotes: 0

Peter Ritchie
Peter Ritchie

Reputation: 35869

You'll get this error if you have two applications, one serializing, and one deserializing and they share a DLL with the serialized type (Measurment) but the shared DLLs are different builds.

Upvotes: 0

Related Questions