Binary Serialization/Deserialization with dictionaries and others class members - c#

I need to serialize/deserialize a class with subclasses in which a member is a dictionary. Another member is a class storing passwords so it can't be XML but binary.
Have found that very nice solution which might be easy and issue-free.
http://theburningmonk.com/2010/05/net-tips-xml-serialize-or-deserialize-dictionary-in-csharp/
But this example (and all the others I have found) have an xml output which is not the right solution for my problem.
So the question is: "how to make datacontract serialization with binary and not xml output?"
Thanx in advance
---ADD---
Even using a filestream with that class:
[DataContract]
public class MyClass
{
// need a parameterless constructor for serialization
public MyClass()
{
MyDictionary = new Dictionary<string, string>();
}
[DataMember]
public Dictionary<string, string> MyDictionary { get; set; }
public int aaaa = 3;
}
and doing
MyClass theclass = new MyClass();
var serializer = new DataContractSerializer(typeof(MyClass));
bool append = true;
using (Stream fileStream = File.Open("aaa.bin", append ? FileMode.Append : FileMode.Create))
{
serializer.WriteObject(fileStream, theclass);
}
the output is XML.

Like Preston Guillot already mentioned in his comment. The DataContractSerializer.WriteObject also accepts a binary writer. Here is an example just for the sake of completeness.
MyClass theClass = new MyClass();
var serializer = new DataContractSerializer(typeof(MyClass));
bool append = true;
using (Stream fileStream = File.Open("aaa.bin", append ? FileMode.Append : FileMode.Create))
{
XmlDictionaryWriter binaryWriter = XmlDictionaryWriter.CreateBinaryWriter(fileStream);
serializer.WriteObject(binaryWriter, theClass);
binaryWriter.Flush();
}

Related

Saving a Dictionary<int, object> in C# - Serialization?

I have a dictionary in c#
private Dictionary<int, UserSessionInfo> userSessionLookupTable = new Dictionary<int, UserSessionInfo>();
Now I have created a dictionary object
this.userSessionLookupTable.Add(userSessionInfoLogin.SessionId, userSessionInfoLogin);
Now I want a generic method to serialize and de-serialize the dictionory to byte array.
Like
public static void Serialize(Dictionary<int, object> dictionary, Stream stream)
{
//Code here
}
and
public static static Dictionary<int, object> Deserialize(Stream stream)
{
//Code here
}
Can anyone help me on this??
Try this....
public static void Serialize<Object>(Object dictionary, Stream stream)
{
try // try to serialize the collection to a file
{
using (stream)
{
// create BinaryFormatter
BinaryFormatter bin = new BinaryFormatter();
// serialize the collection (EmployeeList1) to file (stream)
bin.Serialize(stream, dictionary);
}
}
catch (IOException)
{
}
}
public static Object Deserialize<Object>(Stream stream) where Object : new()
{
Object ret = CreateInstance<Object>();
try
{
using (stream)
{
// create BinaryFormatter
BinaryFormatter bin = new BinaryFormatter();
// deserialize the collection (Employee) from file (stream)
ret = (Object)bin.Deserialize(stream);
}
}
catch (IOException)
{
}
return ret;
}
// function to create instance of T
public static Object CreateInstance<Object>() where Object : new()
{
return (Object)Activator.CreateInstance(typeof(Object));
}
Usage...
Serialize(userSessionLookupTable, File.Open("data.bin", FileMode.Create));
Dictionary<int, UserSessionInfo> deserializeObject = Deserialize<Dictionary<int, UserSessionInfo>>(File.Open("data.bin", FileMode.Open));
I have used 'Object' in the code above to fulfil your requirements but personally I would use 'T' which usually denotes a generic object in C#
You could use a MemoryStream for this purpose unless you don't want to create a file. But for the serializing method, if you don't want to return a value you should probably mark the stream parameter as [Out].
public static void Serialize(Dictionary<int, object> dictionary, [Out] Stream stream)
{
stream = new MemoryStream();
new BinaryFormatter().Serialize(stream, dictionary);
}
public static Dictionary<int, object> Deserialize(Stream stream)
{
return (Dictionary<int, object>)new BinaryFormatter().Deserialize(stream);
}
This will perform binary serialization.
EDIT:
To get it as a byte array you can just cast the stream returned from the Serialize() method to a MemoryStream, and then call .ToArray() on it.
This is an example:
MemoryStream outputStream;
Serialize(your dictionary here, outputStream);
byte[] bytes = outputStream.ToArray();
A bit late to answer maybe but here is a practical and more general answer from my experience: Use simple JSON serialisation if you want something quick and easy or if there is not much demand for data size or performance. If you want something highly space efficient, fast and cross-platform as well, use Google Protocol Buffers.
JSON
string output = JsonConvert.SerializeObject(myObject);
var copyOfMyObject = JsonConvert.DeserializeObject<MyObject>(output);
There are a lot of ways you can control the serialisation and use streams and so on.
Json.Net also supports dictionaries too.
Protobuf
There are two ways of using protobuf in c#: Using .proto message definitions and generate code or reflection based approach using your class definitions and attributes. It depends on your project but I prefer the message definitions personally.
Note that you might have to do your own munging before and after serialisation and deserialisation to use with a Dictionary.
Message definition based: using proto3
.proto file:
message Person {
int32 id = 1;
string name = 2;
}
Generate code using Google Protobuf:
protoc --csharp_out=$DST_DIR $SRC_DIR/person.proto
Serialise / deserialise using generated classes:
Person john = ...;
john.WriteTo(stream);
var copyOfJohn = Person.Parser.ParseFrom(stream);
Also, a quick note to let you know that there is probably a less known feature of proto3 is the capability of using JSON.
Reflection based: Protobuf-net
Here is a quick example (copied from protobuf-net page)
[ProtoContract]
class Person {
[ProtoMember(1)]
public int Id {get;set;}
[ProtoMember(2)]
public string Name {get;set;}
}
Serializer.Serialize(file, person);
newPerson = Serializer.Deserialize<Person>(file);
Binary, text, streams, oh my!
Apologies, I sort of ignored the question about 'Binary' serialisation (and was not a specific BinaryFormatter question) since there are lots of ways you can use streams to deal with data flowing in and out of a process. C# stream, reader and writer and other System.IO APIs are quite well documented.
For Binary Serialization
For more info take a look at BinaryFormatter.
Here is a possible solution:
public void Serialize(Dictionary<int, UserSessionInfo> dictionary, Stream stream)
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(dictionary.Count);
foreach (var obj in dictionary)
{
writer.Write(obj.Key);
writer.Write(obj.Value);
}
writer.Flush();
}
public Dictionary<int, UserSessionInfo> Deserialize(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
int count = reader.ReadInt32();
var dictionary = new Dictionary<int, UserSessionInfo>(count);
for (int n = 0; n < count; n++)
{
var key = reader.ReadInt32();
var value = reader.ReadString();
dictionary.Add(key, value);
}
return dictionary;
}
but you still need to have UserSessionInfo ToString() converter;
For XML Serialization
Create a sample class Session
public class Session
{
[XmlAttribute]
public int SessionID;
[XmlAttribute]
public UserSessionInfo SessionInfo;
}
Then you can create XmlSerializer if you want to serialize it as XML
XmlSerializer serializer = new XmlSerializer(
typeof(Session[]),
new XmlRootAttribute() { ElementName = "sessions" }
);
And now you can serialize or deserialize.
Serialization:
serializer.Serialize(
stream,
dict.Select(kv => new Session(){SessionID = kv.Key, SessionInfo = kv.Info}).ToArray()
);
Deserialization:
var deserialized = (
(Session[])serializer.Deserialize(stream)
).ToDictionary(i => i.id, i => i.info);
But you need to have ToString() method in your UserSessionInfo to store it in the XML.
And the XML may look like this:
<sessions>
<session id='int_goes_here' value='string_goes_here'/>
</sessions>
Hope this helps.
unless you want to build your own completely custom serializer then you need to use the built in serialization structure
The dictionary and all the referenced types must implement the inbuilt serialisation structure which requires classes to be decorated witht the correct attributes ie [Serializable], or [DataContact] and as object can't implement it then you can't serialise it directly, you need to change it to a serializable type

Different field serialization technique in ntext SQL field while keeping backward compatibility

TL, DR: we've been serializing some data in some tables of our SQL DB. Unfortunately that serialization technique wastes a lot of space for markup characters. We've found a new, more efficient way: to keep backwards compatibility, is it safe to adopt the following logic? -> When the serialization occurs, it always occurs using the new, more efficient way. When deserialization occurs, we check whether the string uses the new serialization format or the old one --> we then deserialize with the appropriate method. Is this robust? Can this be used in production? Aren't there any subtle problems with this approach?
Greetings. I'm working on an application which interacts with a SQL database. To achieve a specific business requirement, we've been serializing some data in a special column of our DB tables, of type ntext. Basically, in each cell of this column, we serialize an array of "Attributo" object, so typeof(T) is Attributo[]:
The "Attributo" definition is like the following:
public class Attributo
{
public virtual String Nome { get; set; }
public virtual String Valore { get; set; }
public virtual String Tipologia { get; set; }
}
- Deserialization to read the actual values:
XMLUtilities.Deserialize<Attributo[]>(value));
Serialization to store the values in the column (for each row..):
XMLUtilities.Serialize(attributes.ToArray());
And this is the helper class, which makes use of the XmlSerializer object:
public static class XMLUtilities
{
public static T Deserialize<T>(String xmlString)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlString))
{
return (T) serializer.Deserialize(reader);
}
}
public static String Serialize<T>(T xmlObject)
{
MemoryStream stream = new MemoryStream();
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
serializer.Serialize(stream, xmlObject, xmlnsEmpty);
stream.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
Now, the problem with this technique is that it wastes a lot of space for markup characters. This is an example string which is stored on the db:
<?xml version="1.0"?>
<ArrayOfAttributo>
<Attributo>
<Nome>Leakage_test_Time_prg1_p1</Nome>
<Valore>4</Valore>
<Tipologia>Single</Tipologia>
</Attributo>
<Attributo>
<Nome>Leakage_air_Volume_p1</Nome>
<Valore>14</Valore>
<Tipologia>Single</Tipologia>
</Attributo>
</ArrayOfAttributo>
So, we've found a more concise way of serializing these Attributo[], which produces this kind of output:
<ArrayOfA xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<A>
<N>Leakage_test_Time_prg1_p1</N>
<V>4</V>
<T>Single</T>
</A>
<A>
<N>Leakage_air_Volume_p1</N>
<V>14</V>
<T>Single</T>
</A>
</ArrayOfA>
then, to preserve backwards compatibility, which is the core issue we have implemented the following logic:
During serialization:
we always serialize in the new, more concise fashion
During deserialization:
we check whether the string starts with:
<?xml version="1.0"?>
or not. If that is the case, this is an old entry so we deserialize it in the old way. Otherwise, we deserialize using the new format.
We achieved that by decorating "Attributo" this way:
[DataContract(Name = "A", Namespace= "")]
public class Attributo
{
[DataMember(Name = "N")]
public virtual String Nome { get; set; }
[DataMember(Name = "V")]
public virtual String Valore { get; set; }
[DataMember(Name = "T")]
public virtual String Tipologia { get; set; }
}
and by performing the following changes to our serialization/deserialization methods, which now, for the new serialization technique, rely on DataContractSerializer object:
public static T Deserialize<T>(String xmlString)
{
//let's see if it's an old-style entry...
if (xmlString.StartsWith("<?xml version=\"1.0\"?>\r\n<ArrayOfAttributo>"))
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlString))
{
return (T)serializer.Deserialize(reader);
}
}
catch { }
}
//..then it must be a new-style one
DataContractSerializer ser = new DataContractSerializer(typeof(T));
using (Stream s = _streamFromString(xmlString))
{
return (T) ser.ReadObject(s);
}
}
public static String Serialize<T>(T xmlObject)
{
MemoryStream stream1 = new MemoryStream();
DataContractSerializer ser = new DataContractSerializer(typeof(T));
ser.WriteObject(stream1, xmlObject);
stream1.Position = 0;
StreamReader sr = new StreamReader(stream1);
string xmlString = sr.ReadToEnd();
return xmlString;
}
private static Stream _streamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
Everything seems to be working with this approach but we want to assess every possible risk before proceeding any further. Is this safe to use in production?
One more thing to keep in mind, while deserializing the older entry :
deserialize old-entry in old-style
serialize the old-entry in new-style
save the new-style-serialized-old-entry, and delete the old-style-serialized-old-entry.
You're good to go.

XMLSerialization: The type of the argument object 'Sw' is not primitive

I'm trying to serialize an object to an XML file, but am getting the above error.
The problem seems to be with objects that contain a list of a base class but is populated by objects derived from the base class.
Example code is as follows:
public class myObject
{
public myObject()
{
this.list.Add(new Sw());
}
public List<Units> list = new List<Units>();
}
public class Units
{
public Units()
{
}
}
public class Sw : Units
{
public Sw();
{
}
public void main()
{
myObject myObject = new myObject();
XmlSerializer serializer = new XmlSerializer(typeof(myObject));
TextWriter textWriter = new StreamWriter ("file.xml");
serializer.Serialize (textWriter, myObject);
}
E.g. an object that contains only a List<Units> which is populated by derived objects which inherit from the Units class (Sw).
Sorry for not providing my actual code but the objects involved are quite complex and this seems to be the only part of the object which wont successfully be serialized - and only when the list contains the derived classes.
How can I correctly serialize a class like this?
Mark Units class with XmlInclude attribute passing your derived class as parameter:
[XmlInclude(typeof(Sw))]
public class Units
{
public Units()
{
}
}
To Serialize an object to XML. you can use the following code
public String SerializeResponse(SW sw)
{
try
{
String XmlizedString = null;
XmlSerializer xs = new XmlSerializer(typeof(SW));
//create an instance of the MemoryStream class since we intend to keep the XML string
//in memory instead of saving it to a file.
MemoryStream memoryStream = new MemoryStream();
//XmlTextWriter - fast, non-cached, forward-only way of generating streams or files
//containing XML data
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
//Serialize emp in the xmlTextWriter
xs.Serialize(xmlTextWriter, sw);
//Get the BaseStream of the xmlTextWriter in the Memory Stream
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
//Convert to array
XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
return XmlizedString;
}
catch (Exception ex)
{
throw;
}
}
The method will return an XML String and to make the above function you need to import the following libraries:
using System.Xml;
using System.Xml.Serialization;
using System.IO;

Missing strings in XmlBinaryWriterSession after DataContractSerializer.WriteObject

say I have:
[DataContract(Name=,Namespace=)]
[KnownType(typeof(B))]
class A
{
[DataMember]
public B B{get;set;}
}
[DataContract(Name=,Namespace=)]
class B
{
public string Something{get;set;}
}
...
// ms = memory stream
// writerSession = XmlBinaryWriterSession
using (var writer = XmlDictionaryWriter.CreateBinaryWriter(ms, null, writerSession))
{
var serializer = new DataContractSerializer(typeof(SerializedFeedItem));
serializer.WriteObject(writer, serItem);
writer.Flush();
...
}
For now I see that only type A's xml dictionary strings are added to the writer session. I wonder how can I make the serializer write type B's strings as well.
The question is related to compressing serialized content with XmlDictionary-related technique.
Thanks in advance.

How would I deserialize some class from XML (file), and vice versa?

I have the following class and data members (plus irrelevant methods) I am new to XML and .NET (that excuse is getting old though) and have spent a couple of days reading the MSDN entries (and whatever google turned up) for first XMLReader, then XMLDocument and now XDocument, XElement and XNode but am no closer to a concrete solution to serializing my class (perhaps I need to study serialization in .NET in more depth). To get me started I have some data in an XML file that I want to read (although it prolly is in the wrong format) in to initialize a class to initialize my application. The configuration class is as follows:
class IWantToFile
{
class DirsAndFiles
{
public List<string> Suffixes;
public string Dir;
}
enum OPOptsEnum
{
op1Description, op2Description, op3Description, op4Description,
op5Description, op6Description, op7Description, op8Description,
};
List<DirsAndFiles> ProjectDirs;
bool[] OPOpts = new bool[(int)OPOptsEnum.op8Description + 1];
bool otherOpt;
}
Observing the one to one and one to many relationships therein (eg List<DirsAndFiles> ProjectDirs) can someone please give concise methods to read and write this data to a file? It would greatly assist my development in these fields.
I've got as far as:
if (File.Exists(SPECFILENAME)) {
XDocument xdoc = XDocument.Load(SPECFILENAME);
//Ummm.....
}
but then my lack of .NET XML and Linq exeperience fail me.
I think you might want to use the XmlSerializer, which 'Serializes and deserializes objects into and from XML documents'?
See How to serialize an object to XML by using Visual C# for sample code.
[Serializable]
public class MyObject
{
public string SerializeMe { get; set; }
[XmlIgnore]
public string DONTSerializeMe { get; set; }
}
Helper....
public static class SerializerHelper<T>
{
public static string Serialize(T myobject)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringWriter stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, myobject);
string xml = stringWriter.ToString();
return xml;
}
public static T Deserialize(string xml)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringReader stringReader = new StringReader(xml);
return (T)xmlSerializer.Deserialize(stringReader);
}
}
Usage
MyObject myObject = new MyObject();
string xml = SerializerHelper<MyObject>.Serialize(myObject);
MyObject DeserializedObject = SerializerHelper<MyObject>.Deserialize(xml);

Categories