Reputation: 328
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
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
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
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:
Upvotes: 0
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
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