Binary Serialization to ResultBuffer in C# - c#

I have a working XML Serializer which serializes a C# object to an entity in AutoCAD. I'd like to be able to do the same thing but with Binary Serialization for the cases in which XML does not work. So far my serialization method looks like this:
public static void BinarySave(Entity entityToWriteTo, Object objToSerialize, string key = "default")
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter serializer = new BinaryFormatter();
serializer.Serialize(stream, objToSerialize);
stream.Position = 0;
ResultBuffer data = new ResultBuffer();
/*Code to get binary serialization into result buffer*/
using (Transaction tr = db.TransactionManager.StartTransaction())
{
using (DocumentLock docLock = doc.LockDocument())
{
if (!entityToWriteTo.IsWriteEnabled)
{
entityToWriteTo = tr.GetObject(entityToWriteTo.Id, OpenMode.ForWrite) as Entity;
}
if (entityToWriteTo.ExtensionDictionary == ObjectId.Null)
{
entityToWriteTo.CreateExtensionDictionary();
}
using (DBDictionary dict = tr.GetObject(entityToWriteTo.ExtensionDictionary, OpenMode.ForWrite, false) as DBDictionary)
{
Xrecord xrec;
if (dict.Contains(key))
{
xrec = tr.GetObject(dict.GetAt(key), OpenMode.ForWrite) as Xrecord;
xrec.Data = data;
}
else
{
xrec = new Xrecord();
xrec.Data = data;
dict.SetAt(key, xrec);
tr.AddNewlyCreatedDBObject(xrec, true);
}
xrec.Dispose();
}
tr.Commit();
}
data.Dispose();
}
}
}
It's heavily based on my XML Serializer except I have no idea how to get the serialized object into a resultbuffer to be added to the Xrecord of entityToWriteTo.

If XML isn't working for you for some reason, I'd suggest trying a different textual data format such as JSON. The free and open-source JSON formatter Json.NET has some support for situations that can trip up XmlSerializer, including
Dictionaries.
Classes lacking default constructors.
polymorphic types.
Complex data conversion and remapping.
Plus, JSON is quite readable so you may be able to diagnose problems in your data by visual examination.
That being said, you can convert the output stream from BinaryFormatter to a base64 string using the following helper methods:
public static class BinaryFormatterHelper
{
public static string ToBase64String<T>(T obj)
{
using (var stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, obj);
return Convert.ToBase64String(stream.GetBuffer(), 0, checked((int)stream.Length)); // Throw an exception on overflow.
}
}
public static T FromBase64String<T>(string data)
{
using (var stream = new MemoryStream(Convert.FromBase64String(data)))
{
var formatter = new BinaryFormatter();
var obj = formatter.Deserialize(stream);
if (obj is T)
return (T)obj;
return default(T);
}
}
}
The resulting string can then be stored in a ResultBuffer as you would store an XML string.

Related

Cant deserilize derived class. But it works if it's in a list or a dictionary. Any thoughts?

I got a weird problem where I can serialize a derived class if I put it in a List but not when it stands on it own.
I am using these methods to serialize and deserialize (found them here):
public static string Serialize(T obj)
{
using (MemoryStream memoryStream = new MemoryStream())
using (StreamReader reader = new StreamReader(memoryStream))
{
DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}
public static T Deserialize(string xml, Type toType)
{
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
DataContractSerializer deserializer = new DataContractSerializer(toType);
return (T)deserializer.ReadObject(stream);
}
}
I have a base class Entity. And a derived class Thing.
[DataContract]
[KnownType(typeof(Thing))]
Class Entity
{
}
[DataContract]
Class Thing : Entity
{
}
Now, when I try to serialize an object instantiated as Thing there is no problem but the deserialization gives an error.
Thing e = new Thing();
string xmlstring = XML<Entity>.Serialize(e);
Entity testE = XML<Entity>.Deserialize(xmlstring, typeof(Entity));
The error says something like Expected element Entity from ... . Element Thing was found. (Was not written in english.)
But the weird thing is that it works if I put the object into a list and serialize-deserialize the list.
Thing e = new Thing();
List<Entity> test = new List<Entity>();
test.Add(e);
var xmlstring = XML<List<Entity>>.Serialize(test);
List<Entity> test2 = XML<List<Entity>>.Deserialize(xmlstring, typeof(List<Entity>));
Now test2 has an entry with the a correct Thing-item. Even if this could be a workaround it surely must be an easier way and it must be something that would be easy to fix I think? Any thoughts? What did I miss?
(And of course it works when deserializing my Thingobject as a Thing-object but that's not what I want, when deserializing I will not know the class on beforehand.)
Seems that I have found a workaround myself after thinking about #Jaya's comment. I modified the serialize method to force it to serialize to the base class type. Originally I did not think this would work, but it did!
public static string Serialize(T obj, Type toType)
{
using (MemoryStream memoryStream = new MemoryStream())
using (StreamReader reader = new StreamReader(memoryStream))
{
DataContractSerializer serializer = new DataContractSerializer(toType);
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}

C# Avro Schema not encoded with data stream

I'm using Avro to serialize objects and then add them to Kafka messages that will be consumed and deserialized by clients. I've tried several different approaches for serialization but none of them seem to embed the schema in the data stream. Here is the latest version of my serialization code. You can see the commented out attempts to use the various writers available.
public static byte[] Serialize<T>(T recordObj) where T : ISpecificRecord
{
Log.Info("Serializing {0} object to Avro.", typeof(T));
try
{
using (var ms = new MemoryStream())
{
var encoder = new BinaryEncoder(ms);
//var writer = new SpecificDefaultWriter(recordObj.Schema);
var writer = new SpecificDatumWriter<T>(recordObj.Schema);
//writer.Write(recordObj.Schema, recordObj, encoder);
writer.Write(recordObj, encoder);
return ms.ToArray();
}
}
catch (Exception ex)
{
Log.Error("Failed to Avro serialize object. {0}", ex);
return null;
}
}
I'm not really sure what else to try.
After digging around in the actual Avro code, I found out I needed a FileWriter, but could not figure out how to instantiate one as DataFileWriter has no public constructor. Turns out there is a static method on the DataFileWriter class called OpenWriter which takes in a DatumWriter and a Stream and returns a DataFileWriter. The code below now properly includes object metadata in the result data stream.
public static byte[] Serialize<T>(T recordObj) where T : ISpecificRecord
{
Log.Info("Serializing {0} object to Avro.",typeof(T));
try
{
using(var ms = new MemoryStream())
{
var specDatumWriter = new SpecificDatumWriter<T>(recordObj.Schema);
var specDataWriter = Avro.File.DataFileWriter<T>.OpenWriter(specDatumWriter, ms);
specDataWriter.Append(recordObj);
specDataWriter.Flush();
specDataWriter.Close();
return ms.ToArray();
}
}
catch(Exception ex)
{
Log.Error("Failed to Avro serialize object. {0}",ex);
return null;
}
}

How to deserialize an XML with information about a custom object, using DataContract?

I was able to serialize a List of objects (List) using this code:
public static string Serialize(object obj)
{
using (MemoryStream memoryStream = new MemoryStream())
using (StreamReader reader = new StreamReader(memoryStream))
{
DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}
However, I'm not able to deserialize using this code:
public static object Deserialize(string xml, Type toType)
{
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
DataContractSerializer deserializer = new DataContractSerializer(toType);
return deserializer.ReadObject(stream);
}
}
I'm not able to understand the problem.
I'm using the last method by calling it with:
Deserialize(SerializedObject, List), but I'm getting an error saying List<FilesToProcess> is a type, which is not valid in the given context
Could anyone help? I'm a bit over my head with this.
Sooo, I have the doubtful honor of answering my own question.
The problem was that I was trying to assign the output of
public static object Deserialize(string xml, Type toType)
to a List generic called listOfFiles, when I should have assigned to an object and then cast to a List<FilesToProcess> using
List<FilesToProcess listOfFiles = (List<FilesToProcess)listOfFilesObject;

Saving complex object to IsolatedStorage as XML file in Windows Phone (C#)

I am using this code as my IsolatedStorage Helper.
public class IsolatedStorageHelper
{
public const string MyObjectFile = "History.xml";
public static void WriteToXml<T>(T data, string path)
{
// Write to the Isolated Storage
var xmlWriterSettings = new XmlWriterSettings { Indent = true };
try
{
using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = myIsolatedStorage.OpenFile(path, FileMode.Create))
{
var serializer = new XmlSerializer(typeof(T));
using (var xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
{
serializer.Serialize(xmlWriter, data); //This line generates the exception
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
//Dispatcher.BeginInvoke(() => MessageBox.Show(ex.StackTrace));
//MessageBox.Show(ex.StackTrace);
}
}
public static T ReadFromXml<T>(string path)
{
T data = default(T);
try
{
using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = myIsolatedStorage.OpenFile(path, FileMode.CreateNew))
{
var serializer = new XmlSerializer(typeof(T));
data = (T)serializer.Deserialize(stream);
}
}
}
catch
{
return default(T);
//add some code here
}
return data;
}
}
I am saving an object of my class PdfFile, which has ImageSource as one of its properties.
But an exception is generated while saving the object and it states System.InvalidOperationException: The type System.Windows.Media.Imaging.BitmapImage was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
I would like to know what this means, and how I would solve this.
Thank you
You're trying to serialize a class that contains a variable / property of type BitmapImage. You can't serialize that type, so you get the mentioned exception. Try to work around by serializing a name or something like this and instantiating the BitmapImage on deserialization from that information.
If you want to save something in iso storage which is not serializable then you can still do so if you write your own serialize method.
Presumably the BitmapImage is not an original part of your app or you would already have the file for it, so I guess it must be a newly acquired bitmap.
Convert your BitmapImage to an array of bytes and you should have no problem.

Persist a DataContract as XML in a database

I'm working on a kind of "store and forward" application for WCF services. I want to save the message in a database as a raw XML blob, as XElement. I'm having a bit of trouble converting the datacontract into the XElement type I need for the database call. Any ideas?
this returns it as a string, which you can put into the db into an xml column. Here is a good generic method you can use to serialize datacontracts.
public static string Serialize<T>(T obj)
{
StringBuilder sb = new StringBuilder();
DataContractSerializer ser = new DataContractSerializer(typeof(T));
ser.WriteObject(XmlWriter.Create(sb), obj);
return sb.ToString();
}
btw, are you using linq to sql? The reason i ask is because of the XElement part of your question. if thats the case, you can modify this in the .dbml designer to use a string as the CLR type, and not the default XElement.
The most voted on answer (Jason W. posted) did not work for me. I dont know why that answer got the most votes. But after searching around I found this
http://billrob.com/archive/2010/02/09/datacontractserializer-converting-objects-to-xml-string.aspx
Which worked for my project. I just had a few classes and put the datacontract and datamemeber attributes on classes and properties and then wanted to get an XML string which I could write to the database.
Code from the link above incase it goes 404:
Serializes:
var serializer = new DataContractSerializer(tempData.GetType());
using (var backing = new System.IO.StringWriter())
using (var writer = new System.Xml.XmlTextWriter(backing))
{
serializer.WriteObject(writer, tempData);
data.XmlData = backing.ToString();
}
Deserializes:
var serializer = new DataContractSerializer(typeof(T));
using (var backing = new System.IO.StringReader(data.XmlData))
using (var reader = new System.Xml.XmlTextReader(backing))
{
return serializer.ReadObject(reader) as T;
}
If your database is SQL Server 2005 or above, you can use the XML data type:
private readonly DataContractToSerialize _testContract =
new DataContractToSerialize
{
ID = 1,
Name = "One",
Children =
{
new ChildClassToSerialize {ChildMember = "ChildOne"},
new ChildClassToSerialize {ChildMember = "ChildTwo"}
}
};
public void SerializeDataContract()
{
using (var outputStream = new MemoryStream())
{
using (var writer = XmlWriter.Create(outputStream))
{
var serializer =
new DataContractSerializer(_testContract.GetType());
if (writer != null)
{
serializer.WriteObject(writer, _testContract);
}
}
outputStream.Position = 0;
using (
var conn =
new SqlConnection(Settings.Default.ConnectionString))
{
conn.Open();
const string INSERT_COMMAND =
#"INSERT INTO XmlStore (Data) VALUES (#Data)";
using (var cmd = new SqlCommand(INSERT_COMMAND, conn))
{
using (var reader = XmlReader.Create(outputStream))
{
var xml = new SqlXml(reader);
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#Data", xml);
cmd.ExecuteNonQuery();
}
}
}
}
}
I'm not sure about the most efficient way to get it to an XElement, but to get it to a string just run:
DataContractSerializer serializer = new DataContractSerializer(typeof(Foo));
using (MemoryStream memStream = new MemoryStream())
{
serializer.WriteObject(memStream, fooInstance);
byte[] blob = memStream.ToArray();
}
I tried to use Jason w'Serialize function that uses StringBuilder , but it returns empty string for LingToSQL Designer generated table class
with [DataContract()] attribute
However if I serialze to byte array as suggested by AgileJon
and then use UTF7Encoding to convert to string , it creates readable XML string.
static string DataContractSerializeUsingByteArray<T>(T obj)
{
string sRet = "";
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
using (MemoryStream memStream = new MemoryStream())
{
serializer.WriteObject(memStream, obj);
byte[] blob = memStream.ToArray();
var encoding= new System.Text.UTF7Encoding();
sRet = encoding.GetString(blob);
}
return sRet;
}
Not sure why stringBuilder solution not working.

Categories