Serializing/deserializing with memory stream - c#

I'm having an issue with serializing using memory stream. Here is my code:
/// <summary>
/// serializes the given object into memory stream
/// </summary>
/// <param name="objectType">the object to be serialized</param>
/// <returns>The serialized object as memory stream</returns>
public static MemoryStream SerializeToStream(object objectType)
{
MemoryStream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, objectType);
return stream;
}
/// <summary>
/// deserializes as an object
/// </summary>
/// <param name="stream">the stream to deserialize</param>
/// <returns>the deserialized object</returns>
public static object DeserializeFromStream(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
object objectType = formatter.Deserialize(stream);
return objectType;
}
The error I'm getting is as follow:
stream is not a valid binary format. The starting contents (in bytes) are: blah....
I'm not exactly sure what is causing the error. Any help would be greatly appreciated.
Example of the call:
Dog myDog = new Dog();
myDog.Name= "Foo";
myDog.Color = DogColor.Brown;
MemoryStream stream = SerializeToStream(myDog)
Dog newDog = (Dog)DeserializeFromStream(stream);

This code works for me:
public void Run()
{
Dog myDog = new Dog();
myDog.Name= "Foo";
myDog.Color = DogColor.Brown;
System.Console.WriteLine("{0}", myDog.ToString());
MemoryStream stream = SerializeToStream(myDog);
Dog newDog = (Dog)DeserializeFromStream(stream);
System.Console.WriteLine("{0}", newDog.ToString());
}
Where the types are like this:
[Serializable]
public enum DogColor
{
Brown,
Black,
Mottled
}
[Serializable]
public class Dog
{
public String Name
{
get; set;
}
public DogColor Color
{
get;set;
}
public override String ToString()
{
return String.Format("Dog: {0}/{1}", Name, Color);
}
}
and the utility methods are:
public static MemoryStream SerializeToStream(object o)
{
MemoryStream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, o);
return stream;
}
public static object DeserializeFromStream(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
object o = formatter.Deserialize(stream);
return o;
}

Use Method to Serialize and Deserialize Collection object from memory. This works on Collection Data Types. This Method will Serialize collection of any type to a byte stream. Create a Seperate Class SerilizeDeserialize and add following two methods:
public class SerilizeDeserialize
{
// Serialize collection of any type to a byte stream
public static byte[] Serialize<T>(T obj)
{
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binSerializer = new BinaryFormatter();
binSerializer.Serialize(memStream, obj);
return memStream.ToArray();
}
}
// DSerialize collection of any type to a byte stream
public static T Deserialize<T>(byte[] serializedObj)
{
T obj = default(T);
using (MemoryStream memStream = new MemoryStream(serializedObj))
{
BinaryFormatter binSerializer = new BinaryFormatter();
obj = (T)binSerializer.Deserialize(memStream);
}
return obj;
}
}
How To use these method in your Class:
ArrayList arrayListMem = new ArrayList() { "One", "Two", "Three", "Four", "Five", "Six", "Seven" };
Console.WriteLine("Serializing to Memory : arrayListMem");
byte[] stream = SerilizeDeserialize.Serialize(arrayListMem);
ArrayList arrayListMemDes = new ArrayList();
arrayListMemDes = SerilizeDeserialize.Deserialize<ArrayList>(stream);
Console.WriteLine("DSerializing From Memory : arrayListMemDes");
foreach (var item in arrayListMemDes)
{
Console.WriteLine(item);
}

BinaryFormatter may produce invalid output in some specific cases. For example it will omit unpaired surrogate characters. It may also have problems with values of interface types. Read this documentation page including community content.
If you find your error to be persistent you may want to consider using XML serializer like DataContractSerializer or XmlSerializer.

It can be done easily by using System.Text.Json in .Net 6
using System.Text.Json;
Examlple ex = JsonSerializer.Deserialize<Example>(ms);
Console.WriteLine(ex.Value);
class Example
{
string Value {get; set; }
}
Refer to this for serialization.

Related

Value becomes null when De-serialize with the model after changed to short-hand property in C#

In my solution to serialize data with the model and stored as bit array in SQL and it retrieving the bit array and then Deserialize with the same model. In the model we have done one change. The existing property changed to shorthand property as below.
Existing code
[Serializable()]
public abstract class SearchResultModel : ISearchResultModel
{
private Guid id;
public Guid ID
{
get { return this.id; }
set { this.id = value; }
}
}
And its changed as below
[Serializable()]
public abstract class SearchResultModel : ISearchResultModel
{
public Guid ID { get; set; }
}
The data is serialize and deserialize with both new and old model. But the problem is that when we retrieve old model serialized bit-array trying to deserialize with new Model the ID become GUID.Empty.
The code for serialize and deserialize has no change.
---------------For Deserialize-----
MemoryStream stream = new MemoryStream(searchResultInfoData);
stream.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
var searchResultInfo = (SearchResultModel)formatter.Deserialize(stream);
stream.Flush();
stream.Close();
return searchResultInfo;
---------------For Serialize-----
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, instance); //instance type is Object
stream.Seek(0, 0);
stream.Position = 0; //Return to start
byte[] byteArray = stream.ToArray();
stream.Flush();
stream.Close();
return byteArray;
With the both model data is already stored. How we can resolve this? Did I missing something?

Serialize nested objects in C#

I got 2 user-defined classes, called Event and Image, Event has a property stored a list of EventImage, called EventImages. And in Image class, there's a byte[] type property which store the byte[] of one Image file.
Here's the definitions of the 2 classes :
[Serializable]
public Class Event
{
public String Name {get; set;}
public DateTime EventTime { get; set;}
public List<Image> EventImages { get; set; }
...
}
[Serializable]
public Class Image
{
public DateTime ImageTime { get; set;}
public byte[] pData {get; set;}
...
}
Now my question is, I want to serialize my Event object to byte[], and I expect that the whole content of it will be serialize, too, but it seems that I failed.
Here's my code to do Serialization :
public static byte[] ObjectToByteArray(object obj)
{
if (obj == null)
{
return null;
}
else
{
BinaryFormatter bF = new BinaryFormatter();
using (MemoryStream mS = new MemoryStream())
{
bF.Serialize(mS, obj);
return mS.ToArray();
}
}
}
and here's the code for verification :
Console.WriteLine(ObjectToByteArray(Event));
Console.WriteLine(ObjectToByteArray(Event.EventImage));
Console.WriteLine(ObjectToByteArray(Event.EventImages.FirstOrDefault().pData));
and the results are(just assumption value) :
100 200 300
But I expect the result should be 600(100+200+300), 500(200+300) and 300.
So, I think my serialization doesn't really serialize the whole content, it just serialize properties with Basic Types, but without the nested objects, am I right?
I've searched lots of posts, and I found plenty of answers to similar questions mentioned "XML Serialization", but I'm not sure whether its helpful or not. Need I use that or is there any other better way? Thanks in advance!
Quickly made a test to check equality. It passes.
Serializes and deserializes correctly.
Conclusion, don't judge whether something is happening or not until you've tested it.
public static void Run()
{
var i = new Image
{
ImageTime = DateTime.UtcNow,
pData = Guid.NewGuid().ToByteArray()
};
var e = new Event
{
Name = Guid.NewGuid().ToString(),
EventTime = DateTime.UtcNow,
EventImages = new List<Image> {i}
};
var bytes = ObjectToByteArray(e);
var e2 = ObjectFromByteArray(bytes);
Console.WriteLine(e.Equals(e2));
}
public static byte[] ObjectToByteArray(object obj)
{
if (obj == null)
{
return null;
}
var bF = new BinaryFormatter();
using (var mS = new MemoryStream())
{
bF.Serialize(mS, obj);
return mS.ToArray();
}
}
public static object ObjectFromByteArray(byte[] bytes)
{
if (bytes == null)
{
return null;
}
var bF = new BinaryFormatter();
using (var mS = new MemoryStream(bytes))
{
return bF.Deserialize(mS);
}
}

Serialize and Deserialize object graph using BinaryFormatter

I'm trying to serialize my object graph to a string then deserialize it from a string. The object serializes just fine if I do this
using (var memStream = new System.IO.MemoryStream())
{
mf.Serialize(memStream, this);
memStream.Seek(0, 0);
Search s;
using (var memStrClone = new System.IO.MemoryStream())
{
memStream.CopyTo(memStrClone);
memStrClone.Seek(0, 0);
s = mf.Deserialize(memStrClone) as Search;
}
}
The above code works but serializing to a string and trying to deserialize that same string like this
Search s;
string xml = ToString<Search>(this);
s = FromString<Search>(xml);
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());
}
}
Throws an exception
No assembly ID for object type '1936026741 Core.Sebring.BusinessObjects.Search.Search'.
Any help is greatly appreciated. Thanks.
Here is some code which will do what you want to to (I think) - but I've got to ask - why do you want to serialize to a string like that?
If the class is simple enough to serialise to a string, use an XML serializer which is much easier to deal with; if you want to serialize it out to disk, binary write it out to a file and if it is complicated and you are serializing it to transmit - consider using something like protobuf-net.
I think the crux of your problem is that you are trying to use ASCII encoding - I'm using Base64 encoding.
Anyway - here goes (I've just had a guess at your Search class!)
class Program
{
[Serializable]
public class Search
{
public Guid ID { get; private set; }
public Search() { }
public Search(Guid id)
{
ID = id;
}
public override string ToString()
{
return ID.ToString();
}
}
static void Main(string[] args)
{
Search search = new Search(Guid.NewGuid());
Console.WriteLine(search);
string serialized = SerializeTest.SerializeToString(search);
Search rehydrated = SerializeTest.DeSerializeFromString<Search>(serialized);
Console.WriteLine(rehydrated);
Console.ReadLine();
}
}
public class SerializeTest
{
public static Encoding _Encoding = Encoding.Unicode;
public static string SerializeToString(object obj)
{
byte[] byteArray = BinarySerializeObject(obj);
return Convert.ToBase64String(byteArray);
}
public static T DeSerializeFromString<T>(string input)
{
byte[] byteArray = Convert.FromBase64String(input);
return BinaryDeserializeObject<T>(byteArray);
}
/// <summary>
/// Takes a byte array and deserializes it back to its type of <see cref="T"/>
/// </summary>
/// <typeparam name="T">The Type to deserialize to</typeparam>
/// <param name="serializedType">The object as a byte array</param>
/// <returns>The deserialized type</returns>
public static T BinaryDeserializeObject<T>(byte[] serializedType)
{
if (serializedType == null)
throw new ArgumentNullException("serializedType");
if (serializedType.Length.Equals(0))
throw new ArgumentException("serializedType");
T deserializedObject;
using (MemoryStream memoryStream = new MemoryStream(serializedType))
{
BinaryFormatter deserializer = new BinaryFormatter();
deserializedObject = (T)deserializer.Deserialize(memoryStream);
}
return deserializedObject;
}
/// <summary>
/// Takes an object and serializes it into a byte array
/// </summary>
/// <param name="objectToSerialize">The object to serialize</param>
/// <returns>The object as a <see cref="byte"/> array</returns>
public static byte[] BinarySerializeObject(object objectToSerialize)
{
if (objectToSerialize == null)
throw new ArgumentNullException("objectToSerialize");
byte[] serializedObject;
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, objectToSerialize);
serializedObject = stream.ToArray();
}
return serializedObject;
}
}
HTH

Deserialisation doesn't rebuild dictionaries that are members of classes

I've got some serialisation code set up as follows:
static void SerialiseObject(Object o, String path)
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(path, FileMode.Create);
formatter.Serialize(stream, o);
stream.Close();
}
static Object DeserialiseObject(String path)
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
Object o = (Object)formatter.Deserialize(stream);
stream.Close();
return o;
}
And a class with the following member defined:
[Serializable]
public class CircuitModel
{
public Dictionary<String, Bus> Buses { protected set; get; }
...
}
I populate the Dictionary, and then the following code successfully serialises and deserialises the dictionary, with all Bus objects intact:
SerialiseObject(CircuitModel.Buses, "temp.bin");
Object o = DeserialiseObject("temp.bin");
But when I try to do the same for CircuitModel:
SerialiseObject(CircuitModel, "temp.bin");
Object o = DeserialiseObject("temp.bin");
CircuitModel.Buses has been initialised, but is empty.
I've also tried implementing serialisation with ISerializable (for the Bus and CircuitModel classes) and had exactly the same problem
Any idea as to why this would be happening?
I think you have something more sinister going on with your child collection because binary serialization of Dictionaries within classes does work just fine.
[TestFixture]
public class SerializeTest
{
[Test]
public void TestSer()
{
var parent = new Parent
{
Name = "Test"
};
parent.Children.Add("Child1", new Child {Name = "Child1"});
parent.Children.Add( "Child2", new Child { Name = "Child2" } );
SerialiseObject(parent, "test.bin");
var copy = DeserialiseObject("test.bin") as Parent;
Assert.IsNotNull(copy);
Assert.AreEqual(2, copy.Children.Count);
Assert.IsTrue(copy.Children.ContainsKey("Child1"));
Assert.AreEqual("Child1", copy.Children["Child1"].Name);
}
static void SerialiseObject( Object o, String path )
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream( path, FileMode.Create );
formatter.Serialize( stream, o );
stream.Close();
}
static Object DeserialiseObject( String path )
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream( path, FileMode.Open, FileAccess.Read );
Object o = (Object) formatter.Deserialize( stream );
stream.Close();
return o;
}
[Serializable]
private class Parent
{
public string Name { get; set; }
public Dictionary<string, Child> Children { get; protected set; }
public Parent()
{
Children = new Dictionary<string, Child>();
}
}
[Serializable]
private class Child
{
public string Name { get; set; }
}
}
The children deserialize with the parent and contain the details they were initialized with. I would check any code that is setting your Buses collection. My example just did it in the constructor of the parent class, but it may be possible that you have rogue code setting it after it's been deserialized?
Dictionaries are not serializable. Remove the dictionary if you need to serialize that data, and replace it by a list of a custom class that contains the data in the dictionary:
[Serializable]
public class BusItem
{
public string Name {get;set;}
public Bus Bus {get;set;}
}
Edit: I just found out you can actually serialize Dictionaries using the DataContractSerializer instead.
http://theburningmonk.com/2010/05/net-tips-xml-serialize-or-deserialize-dictionary-in-csharp/
If you are talking about XML serialization, it might be because Dictionary is not serializable to XML. Look at Why isn't there an XML-serializable dictionary in .NET.

Pass in an object reference when Deserializing

I have an object that is deserialized with this:
public object DeSerializeObject(string filename)
{
object objectToSerialize;
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
objectToSerialize = (object)bFormatter.Deserialize(stream);
stream.Close();
return objectToSerialize;
}
public GUI_Settings(SerializationInfo info, StreamingContext ctxt)
{
PrinterFont = (Font)info.GetValue("_printFont", typeof(Font));
}
How could I pass in and object as I deserialize it? Kind of like this
public object DeSerializeObject(string filename, someObject thing)
{
......
objectToSerialize = (object)bFormatter.Deserialize(stream, thing);
.....
}
public GUI_Settings(SerializationInfo info, StreamingContext ctxt, someObject thing)
{
PrinterFont = (Font)info.GetValue("_printFont", typeof(Font));
_thing = thing;
}
I'm not quite sure if I explained it clearly let me try again.
Inside of my main class I say
_settings = (GUI_Settings)new ObjectSerializing()
.DeSerializeObject("Settings.data");
or if I understand what Jalal Aldeen Saa'd said
_settings = (GUI_Settings)ObjectSerializing
.DeserializeFromFile<GUI_Settings>("Settings.data");
When the code runs I need to send it a reference to _backend type backEndInitializer. This reference is held within this main class. GUI_Settings is the type that I am deserializing. _backend is the reference that I need to send the GUI_Settings() method to use.
Answer:
public static object DeSerializeObject(string filename, backEndInitializer backend)
{
object state = backend; // your object
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bFormatter =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(
null,
new System.Runtime.Serialization.StreamingContext(
System.Runtime.Serialization.StreamingContextStates.All,
state)); // pass it in
object objectToSerialize;
Stream stream = File.Open(filename, FileMode.Open);
//BinaryFormatter bFormatter = new BinaryFormatter();
objectToSerialize = (object)bFormatter.Deserialize(stream);
stream.Close();
return objectToSerialize;
}
Then in the class that is being deserialized
public GUI_Settings(SerializationInfo info, StreamingContext ctxt)
{
_backend = (backEndInitializer) ctxt.Context;
}
object state = null; // your object
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(
null,
new System.Runtime.Serialization.StreamingContext(
System.Runtime.Serialization.StreamingContextStates.All,
state)); // pass it in
From there you can access it object in the context argument in your deserialization constructor. The StreamingContext will have a reference to this instance
Use generics to pass the type of the object that will be deserialized:
public static T DeserializeFromFile<T>(string fileName) where T : class
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
BinaryFormatter formatter = new BinaryFormatter();
return (T)formatter.Deserialize(stream);
}
}
Usage:
Thing deserialized = DeserializeFromFile<Thing>(filePath);

Categories