Deserialization from MemoryStream() - c#

Lets say, I have a class with objects in it.
namespace Class_Serialization
{
[Serializable]
public class Data
{
public string Name = "Example1";
public string place = "Torino";
public DateTime time = DateTime.Now;
}
}
I am trying to serialize it using ISerialization interface
[Serializable]
public class SerializeThisClass : ISerializable
{
public Data StreamThisData;
public SerializeThisClass()
{
}
public SerializeThisClass(Data _StreamThisData)
{
StreamThisData = _StreamThisData;
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Object Data", StreamThisData);
}
}
Now, When I serialize with the code below
Data DataToSerialize = new Data();
BinaryFormatter DataToBinary = new BinaryFormatter();
SerializeThisClass serialize = new SerializeThisClass(DataToSerialize);
SerializeIn SerializeInMem = new SerializeIn();
DataToBinary.Serialize(SerializeInMem.StreamOfData, serialize);
ListOfStreams.Add(SerializeInMem);
It serializes normally, but when I try to deserialize it, it gives me error
BinaryFormatter BinaryToData = new BinaryFormatter();
foreach (SerializeIn x in ListOfStreams)
{
x.StreamOfData.Position = 0;
SerializeThisClass DeserializeData = (SerializeThisClass)BinaryToData.Deserialize(x.StreamOfData);
MessageBox.Show("Name: " + DeserializeData.StreamThisData.Name + "\nPlace: " + DeserializeData.StreamThisData.place + "\nDateTime: " + DeserializeData.StreamThisData.time.ToString());
}
Error: $exception{"The constructor to deserialize an object of type
'Class_Serialization.SerializeThisClass' was not found."}
System.Exception {System.Runtime.Serialization.SerializationException}

If you are implementing ISerializable, you need a constructor of the signature:
protected YourType(SerializationInfo information, StreamingContext context) {}
which loads the data (basically, the reverse of GetObjectData). Presumably, with (untested):
StreamThisData = (Data)info.GetValue("Object Data", typeof(Data));

Try adding the constructor:
protected SerializeThisClass(SerializationInfo info, StreamingContext context)
{
}
http://msdn.microsoft.com/en-us/library/ms182343(v=vs.80).aspx

Related

Deserializtion return empty object, using Filestream and Binary Formatter

The problem is that i get zero count in repo when deserialize it (without any errors)
[Serializable]
class RegexRepository : Dictionary<string, string>
{
public RegexRepository()
{
//this.Add("All", "ALL");
//this.Add("Name", #"Name:(?<data>[\s\w]+)Email");
//this.Add("Email", #"Email:(?<data>[\w\s#]+\.com)");
//this.Add("Phone Number", "Phone:(?<data>\\d+)");
}
protected RegexRepository(SerializationInfo info, StreamingContext context)
{
}
private static RegexRepository repo = new RegexRepository();
public static RegexRepository Instance
{
get
{
if (repo == null)
{
repo = new RegexRepository();
}
return repo;
}
}
string FileName = AppDomain.CurrentDomain.BaseDirectory + "BinaryFile.dat";
public void Serialize()
{
using (FileStream ms = new FileStream(FileName, FileMode.OpenOrCreate))
{
var bf = new BinaryFormatter();
bf.Serialize(ms, this);
}
}
public void Deserialize()
{
if (System.IO.File.Exists(FileName))
{
using (FileStream ms = new FileStream(FileName, FileMode.Open))
{
var bf = new BinaryFormatter();
repo = (RegexRepository)bf.Deserialize(ms);
//Here i get zero count in repo, checked while debugging
}
}
}
}
I have seen BinaryFile.dat is not empty and i can see some records in it. Kindly help me
You need to call the base constructor from your streaming constructor:
protected RegexRepository(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
Also, FileName probably should not be a field, you're allocating memory for it in your class, which is not necessary. Instead a static property would seem to make more sense:
static string FileName
{
get
{
return AppDomain.CurrentDomain.BaseDirectory + "BinaryFile.dat";
}
}
When the base class implements ISerializable, it isn't enough to just slap a [Serializable] attribute on a derived class. Your derived class needs to:
Call base(info, context) from the (currently empty) serialization constructor.
Fill in your serialization constructor to read any instance values from the SerializationInfo.
Create a GetObjectData(SerializationInfo info, StreamingContext context) override to write derived members to SerializationInfo (and call the base class' implementation).
Running VS code analysis on your class will light up the problems.

C# Is there a way to exclude a member from serialization dynamically?

C# Is there a way to exclude a member from serialization dynamically?
e.g. (I make up this code, not real)
class def:
[Serializable]
public class Class1
{
public int Property1{get;set;}
}
and I do
Class1 c=new Class(){Property1=15};
SerializationOption option = new SerializationOption(){ExludeList=new List(){"Property1"}};
var result=Serialize(Class1,option);
The only way to control this is to implement ISerializable on the class and have access to some context during serialization. For example:
public class Class1 : ISerializable
{
// ....
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
var excludeList = (List<String>)context.Context;
if(!excludeList.Contains("Property1"))
{
info.AddValue("Property1",Property1);
}
}
}
You provide this context during creating of the formatter. For example:
var sc = new StreamingContext(StreamingContextStates.All,
new List<String> { "Property1" });
var formatter = new BinaryFormatter(null, sc);

Serialization of List<IMyInterface> using ISerializable

Thanks for taking a look!
I'm working on a new version of a product that is deployed in the field. I need to maintain the ability to deserialize exiting files from the older software.
Here is a contrived example:
I have a existing customer base with serialized files that they need to access. For the purposes of this question, they have a "Zoo" file with a List of Giraffes in it.
[Serializable]
public class Giraffe
: ISerializable
{
public int Age { get; private set; }
public Giraffe(int age)
{
Age = age;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Age", Age);
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
private Giraffe(SerializationInfo info, StreamingContext context)
{
Age = info.GetInt32("Age");
}
}
Now, we are deploying a new version of our "Zoo" software, and we are going to support anaimals other than Giraffes, we should have done this to begin with, but due to time constrains, we had to release 1.0 with a Giraffe-only feature set.
public interface IAnimal
{
int Age { get; }
}
[Serializable]
public class Animal
: IAnimal,
ISerializable
{
public int Age { get; private set; }
public Animal (int age)
{
Age = age;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Age", Age);
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
private Animal(SerializationInfo info, StreamingContext context)
{
Age = info.GetInt32("Age");
}
}
I'm using a custom serializationBinder to have old Giraffes deserialized as Animals
public class LegacyZooSerializationBinder
: SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
if (typeName.StartsWith("Test.Giraffe"))
return typeof(Animal);
else if (typeName.StartsWith("System.Collections.Generic.List`1[[Test.Giraffe"))
return typeof(List<Animal>);
else return null;
}
}
The problem is that I wan't to have my Zoo class use a List as it's storage, not a List. I want to do this for two reasons, for future extendability, also, so that I can more easily mock things out for unit testing.
Deserializing the new IAnimal list is no problem. The problem comes when I want to deserialize the old style items. The Binder returns the correct type, the correct deserialization constructor is called, everything looks ok, but the List is actually full of null items. Once the IDeserializationCallback.OnDeserialization callback is called, the list is correct. I can't simply call IEnumerable.ConvertAll<>() on it, because it looks like the serialization framework is trying to find the exact same instance when it comes back to clean everything up, and ConvertAll will create a new list.
I have it working as of now, but I hope someone out there can help me clean this up, as it is not all that maintainable as of now. Here is what it takes to do it:
[Serializable]
public class Zoo
: ISerializable,
IDeserializationCallback
{
List<IAnimal> m_List = null;
List<Giraffe> m_LegacyList = null; //Just so that we can save an old-style zoo
//Temp copy of the list
List<Animal> m_List_Deserialization_Temp_Copy = null;
public Zoo(bool legacy)
{
m_List = new List<IAnimal>();
if (legacy)
{
//Create an old style zoo, just for the example
m_LegacyList = new List<Giraffe>();
m_LegacyList.Add(new Giraffe(0));
m_LegacyList.Add(new Giraffe(1));
}
else
{
m_List.Add(new Animal(0));
m_List.Add(new Animal(1));
}
}
public List<IAnimal> List
{
get { return m_List; }
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
if(m_LegacyList != null) //Save as an old style list if we have old data
info.AddValue("list", m_LegacyList);
else
info.AddValue("list", m_List);
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
private Zoo(SerializationInfo info, StreamingContext context)
{
try
{
//New style
m_List = (List<IAnimal>)info.GetValue("list", typeof(List<IAnimal>));
}
catch (InvalidCastException)
{
//Old style
//Put it in a temp list, until the OnDeserialization callback is called, this will be a list, full of null items!
m_List_Deserialization_Temp_Copy = (List<Animal>)info.GetValue("list", typeof(List<Animal>));
}
}
void IDeserializationCallback.OnDeserialization(object sender)
{
if (m_List_Deserialization_Temp_Copy != null)
{
m_List = new List<IAnimal>();
//This works because IEnumerable<Animal> is covariant to IEnumerable<IAnimal>
m_List.AddRange(m_List_Deserialization_Temp_Copy);
}
}
}
Here is a basic test console app that shows serialization and deserialization for both cases:
static void Main(string[] args)
{
{
var item = new Zoo(false);
var formatter = new BinaryFormatter();
var stream = new MemoryStream();
formatter.Serialize(stream, item);
stream.Position = 0;
formatter.Binder = new LegacyZooSerializationBinder();
var deserialized = (Zoo)formatter.Deserialize(stream);
Debug.Assert(deserialized.List.Count == 2);
Debug.Assert(deserialized.List[0] != null);
Debug.Assert(deserialized.List[0].Age == 0);
Debug.Assert(deserialized.List[1] != null);
Debug.Assert(deserialized.List[1].Age == 1);
Console.WriteLine("New-style Zoo serialization OK.");
}
{
var item = new Zoo(true);
var formatter = new BinaryFormatter();
var stream = new MemoryStream();
formatter.Serialize(stream, item);
stream.Position = 0;
formatter.Binder = new LegacyZooSerializationBinder();
var deserialized = (Zoo)formatter.Deserialize(stream);
Debug.Assert(deserialized.List.Count == 2);
Debug.Assert(deserialized.List[0] != null);
Debug.Assert(deserialized.List[0].Age == 0);
Debug.Assert(deserialized.List[1] != null);
Debug.Assert(deserialized.List[1].Age == 1);
Console.WriteLine("Old-style Zoo serialization OK.");
}
Console.ReadKey();
}
Any suggestions would be greatly appreciated. I'm having a hard time finding good resources on this type of thing. Thanks!
Consider doing a one time conversion from the old files to the new format, preferably at install time and definitely after backing them up. That way you dont have to support this weird one-off serialization forever, and your codebase becomes drastically simpler.

.NET Serializable entity

I need to make all my entities serializable. So I was thinking in a BaseEntity with a Backup and a Restore method. But in the restore I can't override the object with the saved one because this is read-only.
Any solution or some other way to get the serializable entities?
My code:
internal class BaseEntity
{
private MemoryStream ms = new MemoryStream();
private BinaryFormatter bf = new BinaryFormatter();
public void Backup()
{
bf.Serialize(ms, this);
}
public void Restore()
{
this = (BaseEntity)bf.Deserialize(ms);
}
}
The more common pattern is to not make it the responsibility of your objects to serialize/deserialize themselves; rather, use an external serializer:
var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;
serializer.WriteObject(stream, yourObj);
var restoredObj = serializer.ReadObject(stream);
Edit: One way serialization can work is to use the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter (or other implementation of IFormatter). To serialize an object you pass the object and a stream. To Deserialize the object, you pass a stream (positioned at the begining of your serialized data), and it returns the serialized object and all its depenedencies.
public static class EntityBackupServices
{
public static MemoryStream Backup (BaseEntity entity)
{
var ms = new MemoryStream();
Serialize (ms, entity);
ms.Position = 0;
return ms;
}
public static void Serialize (Stream stream, BaseEntity entity)
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize (stream, entity);
}
public static BaseEntity Restore (Stream stream)
{
var binaryFormatter = new BinaryFormatter();
var entity = (BaseEntity) binaryFormatter.Deserialize (stream);
return entity;
}
}
One thing a formatter don't do (though the FormatterServices class makes it possible) is modify existing objects. So you probably don't want to have an instance method called Deserialize. You can't really do this: new LionEntity().Deserialize () where it replaces the fields of an existing instance.
Note: You'll need to put Serializable over all your types. Any fields that can't be serialized (because it's either not a struct, or it's not marked as [Serializable] will need to be marked with NonSerialized.
// A test object that needs to be serialized.
[Serializable()]
public class BaseEntity
{
public int member1;
public string member2;
public string member3;
public double member4;
// A field that is not serialized.
[NonSerialized()] public MyRuntimeType memberThatIsNotSerializable;
public TestSimpleObject()
{
member1 = 11;
member2 = "hello";
member3 = "hello";
member4 = 3.14159265;
memberThatIsNotSerializable = new Form ();
}
public MemoryStream Backup ()
{
return EntityBackupServices.Backup (this);
}
}
Edit:
The way I've mentioned is a rather standard and accepted way. If you want to venture into hackdom, you can deserialize the object the way I've mentioned, then use reflection to set each field on your existing object to the value of the deserialized object.
public class BaseEntity
{
void Restore(Stream stream)
{
object deserialized = EntityBackupServices.RestoreDeserialize(stream);//As listed above
if (deserialized.GetType () != this.GetType ())
throw new Exception();
foreach (FieldInfo fi in GetType().GetFields())
{
fi.SetValue(this, fi.GetValue (deserialized));
}
}
}
public IEntidadBase Restore()
{
return (IEntidadBase)bf.Deserialize(ms);
}
#jacklondon how would you do EntitySerializer methods?
You can do serialization process with http://www.servicestack.net/ StackService.Text module for clean entities. You don't need any attribute (serializable/datacontract) in ms way.
public class EntityFoo
{
public string Bar { get; set; }
public EntityFoo (string bar)
{
Bar = bar;
}
}
public class EntityDumper //and the EntitySerializer
{
public static string Dump<T> (T entity)
{
return new TypeSerializer<T> ().SerializeToString (entity);
}
public static T LoadBack<T> (string dump)
{
return new TypeSerializer<T> ().DeserializeFromString (dump);
}
}
public class dump_usage
{
public void start ()
{
string dump = EntityDumper.Dump (new EntityFoo ("Space"));
EntityFoo loaded = EntityDumper.LoadBack<EntityFoo> (dump);
Debug.Assert (loaded.Bar == "Space");
}
}
I don't necessarily recommend this, but here is one pattern for an object that can persist and restore its own state using serialization that creates new instances:
public sealed class MyClass
{
private Data _data = new Data();
//Properties go here (access the public fields on _data)
public void Backup()
{
//Serialize Data
}
public void Restore()
{
//Deserialize Data and set new instance
}
private sealed class Data
{
//Public fields go here (they're private externally [because Data is private], but public to MyClass.)
}
}
Note that this only works if your serializer supports non-public classes. Worst-case, you have to make the nested class public, which is ugly, but doesn't hurt encapsulation (since the instance is private).

Exception converting surrogate type created in ISerializable.GetObjectData when object is field in a Serializable class

I have a value object class (UserData) that is marked as Serializable and contains another class (StringType) that is marked as Serializable and implements ISerializable so that it can return singleton instances. The StringType class serializes and deserializes fine on it's own, but when it is used as a property on another object that is marked as Serializable, I get an exception truing to convert from the helper class deserialize into a singleton.
Object of type 'Spring2.Core.Test.Serialization.StringType_DEFAULT' cannot be converted to type 'Spring2.Core.Test.Serialization.StringType'.
I am using a BinaryFormatter and need to use that so that I can store this UserData object in an ASP.NET session using SQL server storage.
Here is a very stripped down version of the StringType class as well as some tests that show that serialization/deserialization work for StringType by itself, but not when as a field on UserData.
StringType:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace Spring2.Core.Test.Serialization {
public enum TypeState : short {
DEFAULT,
VALID,
UNSET
}
[Serializable]
public struct StringType : ISerializable {
private string myValue;
private TypeState myState;
public static readonly StringType DEFAULT = new StringType(TypeState.DEFAULT);
public static readonly StringType UNSET = new StringType(TypeState.UNSET);
private StringType(TypeState state) {
myState = state;
myValue = "";
}
public StringType(String s) {
myValue = s;
myState = TypeState.VALID;
}
public bool IsValid {
get { return myState == TypeState.VALID; }
}
public bool IsDefault {
get { return myState == TypeState.DEFAULT; }
}
public bool IsUnset {
get { return myState == TypeState.UNSET; }
}
public override string ToString() {
return IsValid ? this.myValue : myState.ToString();
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
StringType(SerializationInfo info, StreamingContext context) {
myValue = (System.String)info.GetValue("myValue", typeof(System.String));
myState = (TypeState)info.GetValue("myState", typeof(TypeState));
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
if (this.Equals(DEFAULT)) {
info.SetType(typeof(StringType_DEFAULT));
} else if (this.Equals(UNSET)) {
info.SetType(typeof(StringType_UNSET));
} else {
info.SetType(typeof(StringType));
info.AddValue("myValue", myValue);
info.AddValue("myState", myState);
}
}
}
[Serializable]
public class StringType_DEFAULT : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.DEFAULT;
}
}
[Serializable]
public class StringType_UNSET : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.UNSET;
}
}
}
Tests:
using System;
using NUnit.Framework;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Spring2.Core.Test.Serialization {
/// <summary>
/// Tests for BooleanType
/// </summary>
[TestFixture]
public class DataTypeSerializationTest {
[Test]
public void ShouldBinarySerializeStringTypeWithValue() {
BinaryFormatter binaryFmt = new BinaryFormatter();
StringType s = new StringType("foo");
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, s);
fs.Close();
Console.WriteLine("Original value: {0}", s.ToString());
// Deserialize.
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
StringType s2 = (StringType)binaryFmt.Deserialize(fs);
Console.WriteLine("New value: {0}", s2.ToString());
fs.Close();
Assert.AreEqual(s.ToString(), s2.ToString());
}
[Test]
public void ShouldBinarySerializeStringTypeUnset() {
BinaryFormatter binaryFmt = new BinaryFormatter();
StringType s = StringType.UNSET;
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, s);
fs.Close();
Console.WriteLine("Original value is UNSET: {0}", s.IsUnset);
// Deserialize.
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
StringType s2 = (StringType)binaryFmt.Deserialize(fs);
Console.WriteLine("new value is UNSET: {0}", s2.IsUnset);
fs.Close();
Assert.IsTrue(s2.IsUnset);
}
[Test]
public void ShouldDeserializeDataObject() {
BinaryFormatter binaryFmt = new BinaryFormatter();
UserData u = new UserData();
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, u);
fs.Close();
Console.WriteLine("Original value is UNSET: {0}", u.Name.IsUnset);
// Deserialize.
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
Object o = binaryFmt.Deserialize(fs);
UserData u2 = (UserData)o;
Console.WriteLine("new value is UNSET: {0}", u2.Name.IsUnset);
fs.Close();
Assert.IsTrue(Object.Equals(u, u2));
}
}
[Serializable]
public class UserData {
private StringType name = StringType.DEFAULT;
public StringType Name {
get { return name; }
set { name = value; }
}
}
}
Any help would be MUCH appreciated!
Cort
Cort you should change your IObjectReference implementations to return a struct. The third unit test will fail, but it fails on the assertion of the Objects being equal, rather than throwing the type mismatch exception.
[Serializable]
public struct StringType_DEFAULT : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.DEFAULT;
}
}
[Serializable]
public struct StringType_UNSET : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.UNSET;
}
}
You need to change StringType to be a class instead of a struct.
Since your DEFAULT and UNSET StringTypes are static readonly and constructed with the class, you shouldn't need to serialize them at all. Attribute them as [field:nonserialized].
Additionally, unless you have specific logic that needs to happen, you don't need to implement ISerializable for this class. Attributing it as [Serializable] should be enough.

Categories

Resources