How does marking classes as [Serializable] work in C#? - c#

I made a class called MyData and marked it with [Serializable], but it doesn't seem to work...
Here's MyData.cs:
namespace Forms_Bot_Rebuild
{
[Serializable]
public class MyData
{
private String _Email;
private String _Password;
private String _WorldId;
public MyData(string email, string password, string worldid)
{
_Email = email;
_Password = password;
_WorldId = worldid;
}
public string Email
{ get { return _Email; } set { _Email = value; } }
public string Password
{ get { return _Password; } set { _Password = value; } }
public string WorldId
{ get { return _WorldId; } set { _WorldId = value; } }
}
}
Here's Form1.cs:
private void button1_Click(object sender, EventArgs e)
{
MyData data = new MyData(boxEmail.Text, boxPass.Text, boxWorldId.Text);
string objectNode = Serialize.ToJsonString(data);
File.WriteAllText(Application.StartupPath + #"\LoginData.json", objectNode);
}
private void button2_Click(object sender, EventArgs e)
{
object myData;
myData = Serialize.Deserialize<MyData>(new FileStream(Application.StartupPath + #"\LoginData.json", FileMode.Open));
boxEmail.Text = data.Email;
boxPass.Text = data.Password;
boxWorldId.Text = data.WorldId;
}
Here's Serialize.cs:
public class Serialize
{
public static StreamReader ToStreamReader(object o)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(o.GetType());
ser.WriteObject(stream, o);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr;
}
public static string ToJsonString(object o)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(o.GetType());
ser.WriteObject(stream, o);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
public static object Deserialize<T>(Stream stream)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
stream.Position = 0;
T t = (T)ser.ReadObject(stream);
return t;
}
}
Also, this code was given to me by a friend, so I asked him. He couldn't understand it too. I asked another friend, who, in my opinion, knew decent C#, but he couldn't fix it too.
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll
Additional information: Expecting element 'root' from namespace ''.. Encountered 'None' with name '', namespace ''.
Any opinions?

You should use
[DataContract]
instead of
[Serializable]
and mark all the properties with
[DataMember]
(but funnily, on my PC works even with Serializable, only it serializes fields instead of properties... Mmmh I see someone else noticed it: http://pietschsoft.com/post/2008/02/27/NET-35-JSON-Serialization-using-the-DataContractJsonSerializer)
Note that Deserialize could have this signature:
public T Deserialize<T>(Stream stream)
and you should close streams after using them:
MyData myData;
using (var fs = new FileStream(Application.StartupPath + #"\LoginData.json""LoginData.json", FileMode.Open))
{
myData = (MyData)Serialize.Deserialize<MyData>(fs);
}
If instead you really want to know what you wrote in the title:
Each serialization class/method look for "its" serialization attributes (at this time there are at least three families of attributes in Microsoft .NET: [Serializable], the [Xml*] family, the [DataContract]. Plus if you use JSON.NET there are its [Json*] attributes. Stop. So depending on the class/method you want to use to serialize your data, you have to know which attributes it will look for.

Related

How to to serialize a class with a private dictionary member into a file?

I am trying to write functions that save a type, the Dispatcher type shown below, into a file, and then reload it later. I wrote that following functions, but they are not working. I get an exception:
Exception thrown: 'System.InvalidOperationException' in System.Xml.dll
Elsewhere I read that maybe because the member in the class is private then I should use BinaryFormatter, but it did not work.
What am I doing wrong ?
(The Dispatcher class will be used to store messages and also will allow users to pull messages from it. so I want to backup the data in case of an error and then be able to reload it).
public class Dispatcher
{
private Dictionary<int, Dictionary<int, Dictionary<int, Message>>> m_DataBase;
private Dispatcher()
{
m_DataBase = new Dictionary<int, Dictionary<int, Dictionary<int, Message>>>();
}
public static Dispatcher LoadFromFile()
{
Dispatcher loadedDataBase;
try
{
using (Stream stream = new FileStream(#".\DispatcherDataBase.xml", FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(Dispatcher));
loadedDataBase = serializer.Deserialize(stream) as Dispatcher;
}
}
catch (Exception)
{
loadedDataBase = new Dispatcher();
}
return loadedDataBase;
}
public void SaveToFile()
{
FileMode wantedFileModeForStream;
try
{
if (File.Exists(#".\DispatcherDataBase.xml"))
{
wantedFileModeForStream = FileMode.Truncate;
}
else
{
wantedFileModeForStream = FileMode.CreateNew;
}
using (Stream stream = new FileStream(#".\DispatcherDataBase.xml", wantedFileModeForStream))
{
XmlSerializer serializer = new XmlSerializer(this.GetType());
serializer.Serialize(stream, this);
}
}
catch (Exception)
{
}
}
}
You are trying to use XmlSerializer to serialize your Dispatcher type and are encountering three separate problems:
XmlSerializer requires your type to have a public parameterless constructor.
XmlSerializer does not support dictionaries.
XmlSerializer will not serialize non-public members such as m_DataBase.
DataContractSerializer (as well as DataContractJsonSerializer) do not have these limitations. If you mark your Dispatcher type with data contract attributes you will be able to serialize it to XML using this serializer.
Thus if you modify your type as follows:
public static class Constants
{
public const string DataContractNamespace = ""; // Or whatever
}
[DataContract(Name = "Dispatcher", Namespace = Constants.DataContractNamespace)]
public partial class Dispatcher
{
[DataMember]
private Dictionary<int, Dictionary<int, Dictionary<int, Message>>> m_DataBase;
private Dispatcher()
{
m_DataBase = new Dictionary<int, Dictionary<int, Dictionary<int, Message>>>();
}
[System.Runtime.Serialization.OnDeserialized]
void OnDeserializedMethod(System.Runtime.Serialization.StreamingContext context)
{
// Ensure m_DataBase is not null after deserialization (DataContractSerializer does not call the constructor).
if (m_DataBase == null)
m_DataBase = new Dictionary<int, Dictionary<int, Dictionary<int, Message>>>();
}
internal const string FileName = #"DispatcherDataBase.xml";
public static Dispatcher LoadFromFile()
{
Dispatcher loadedDataBase;
try
{
using (var stream = new FileStream(FileName, FileMode.Open))
{
var serializer = new DataContractSerializer(typeof(Dispatcher));
loadedDataBase = serializer.ReadObject(stream) as Dispatcher;
}
}
catch (Exception)
{
loadedDataBase = new Dispatcher();
}
return loadedDataBase;
}
public void SaveToFile()
{
using (var stream = new FileStream(FileName, FileMode.Create))
using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true })) // Optional indentation for readability only.
{
var serializer = new DataContractSerializer(this.GetType());
serializer.WriteObject(writer, this);
}
}
}
// Not shown in question, added as an example
[DataContract(Name = "Message", Namespace = Constants.DataContractNamespace)]
public class Message
{
[DataMember]
public string Value { get; set; }
}
You will be able to round-trip your Dispatcher class to XML. Demo fiddle #1 here.
Alternatively, you could use DataContractJsonSerializer and serialize to JSON by simply swapping serializers and eliminating the optional XmlWriter:
public static Dispatcher LoadFromFile()
{
Dispatcher loadedDataBase;
try
{
using (var stream = new FileStream(FileName, FileMode.Open))
{
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Dispatcher));
loadedDataBase = serializer.ReadObject(stream) as Dispatcher;
}
}
catch (Exception)
{
loadedDataBase = new Dispatcher();
}
return loadedDataBase;
}
public void SaveToFile()
{
using (var stream = new FileStream(FileName, FileMode.Create))
{
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(this.GetType());
serializer.WriteObject(stream, this);
}
}
Demo fiddle #2 here, which results in a fairly simple, clean-looking serialization format:
{"m_DataBase":[{"Key":1,"Value":[{"Key":2,"Value":[{"Key":3,"Value":{"Value":"hello"}}]}]}]}
json.net could also be used to serialize this type if you are willing to use a 3rd party component.

Deserialize object from binary file

Hey guys I am working on a program that will take a person's name and comment and then serialize it to a binary file. It must also be able to deserialize and load the data to the form. I need it to be able to go up and down the list of files(names and comments) by using buttons on the form.
In my code I have it separated into a class that builds the object and the code for the form, and no i'm not allowed to separate it. (Just in case anyone thought that'd work)
the form code:
private void btnAdd_Click(object sender, EventArgs e)
{
bool blnValid = true;
if (string.IsNullOrWhiteSpace(txtName.Text))
{
MessageBox.Show("Please enter a valid name");
}
if (string.IsNullOrWhiteSpace(txtComment.Text))
{
MessageBox.Show("Please enter a valid comment");
blnValid = false;
}
if (blnValid)
{
//create class instance and assign property values
//set file name
DateTime CurrentDate = DateTime.Now;
string strFileName;
strFileName = CurrentDate.ToString("dd-MM-yy-hh-mm-ss") + ".bin";
// serialize object to binary file
MessageBox.Show(strFileName);
Enquiry newEnquiry = new Enquiry();
newEnquiry.Name = txtName.Text;
newEnquiry.Comment = txtComment.Text;
newEnquiry.DOB = dteDOB.Value;
newEnquiry.WriteToFile(strFileName, newEnquiry);
}
}
private void btnLoad_Click(object sender, EventArgs e)
{
}
private void btnPrevious_Click(object sender, EventArgs e)
{
}
and the class code:
[Serializable]
class Enquiry
{
//stores the various values into the enquiry class.
public string Name { get; set; }
public DateTime DOB { get; set; }
public string Comment { get; set; }
//creates the file, if there isn't one, writes the file, and
//disables sharing while the program is active. It also formats
//the file into binary
public void WriteToFile(string strFileName, Enquiry newEnquiry)
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, newEnquiry);
stream.Close();
}
// this loads the files and translates them to plain text
public void ReadFromFile(string strFileName, Enquiry newEnquiry)
{
Stream stream = File.OpenRead(strFileName);
BinaryFormatter formatter = new BinaryFormatter();
newEnquiry = (Enquiry)formatter.Deserialize(stream);
stream.Close();
}
I don't know what you are asking, but if you need methods to serialize and deserialize, use these:
public static void BinarySerializeObject(string path, object obj)
{
using (StreamWriter streamWriter = new StreamWriter(path))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
try
{
binaryFormatter.Serialize(streamWriter.BaseStream, obj);
}
catch (SerializationException ex)
{
throw new SerializationException(((object) ex).ToString() + "\n" + ex.Source);
}
}
}
public static object BinaryDeserializeObject(string path)
{
using (StreamReader streamReader = new StreamReader(path))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
object obj;
try
{
obj = binaryFormatter.Deserialize(streamReader.BaseStream);
}
catch (SerializationException ex)
{
throw new SerializationException(((object) ex).ToString() + "\n" + ex.Source);
}
return obj;
}
}

Is there any design pattern available when using XML serialization in C#

I am using Serialization and De serialization for parsing and creating XML content. Is there any Design pattern available particularly for this serialization in C# , so that the design pattern can be used for efficient handling of serialization ?
Depending on the use case, 'DataContract' may be a good way for you to serialize/deserialize your objects -
https://msdn.microsoft.com/en-us/library/vstudio/system.runtime.serialization.datacontractattribute%28v=vs.100%29.aspx
namespace DataContractAttributeExample
{
// Set the Name and Namespace properties to new values.
[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
class Person : IExtensibleDataObject
{
// To implement the IExtensibleDataObject interface, you must also
// implement the ExtensionData property.
private ExtensionDataObject extensionDataObjectValue;
public ExtensionDataObject ExtensionData
{
get
{
return extensionDataObjectValue;
}
set
{
extensionDataObjectValue = value;
}
}
[DataMember(Name = "CustName")]
internal string Name;
[DataMember(Name = "CustID")]
internal int ID;
public Person(string newName, int newID)
{
Name = newName;
ID = newID;
}
}
class Test
{
public static void Main()
{
try
{
WriteObject("DataContractExample.xml");
ReadObject("DataContractExample.xml");
Console.WriteLine("Press Enter to end");
Console.ReadLine();
}
catch (SerializationException se)
{
Console.WriteLine
("The serialization operation failed. Reason: {0}",
se.Message);
Console.WriteLine(se.Data);
Console.ReadLine();
}
}
public static void WriteObject(string path)
{
// Create a new instance of the Person class and
// serialize it to an XML file.
Person p1 = new Person("Mary", 1);
// Create a new instance of a StreamWriter
// to read and write the data.
FileStream fs = new FileStream(path,
FileMode.Create);
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs);
DataContractSerializer ser =
new DataContractSerializer(typeof(Person));
ser.WriteObject(writer, p1);
Console.WriteLine("Finished writing object.");
writer.Close();
fs.Close();
}
public static void ReadObject(string path)
{
// Deserialize an instance of the Person class
// from an XML file. First create an instance of the
// XmlDictionaryReader.
FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
// Create the DataContractSerializer instance.
DataContractSerializer ser =
new DataContractSerializer(typeof(Person));
// Deserialize the data and read it from the instance.
Person newPerson = (Person)ser.ReadObject(reader);
Console.WriteLine("Reading this object:");
Console.WriteLine(String.Format("{0}, ID: {1}",
newPerson.Name, newPerson.ID));
fs.Close();
}
}
}

C# XmlSerialisation addin serialisation

I have written an Interface for writing a very very simple Plugin. In fact it is just a class that is loaded at runtime out of a dll file and is stored as Property in another class. That class that stores the interface has to get serialized. As example this is my serialized object:
<?xml version="1.0" encoding="utf-8"?><MD5HashMapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.namespace.net" />
But now If i want to load that Object I get an Exception:
As example :
{"<MD5HashMapper xmlns='http://www.vrz.net/Vrz.Map'> was not expected."}
So does anyone has an idea how to solve that problem?
Code:
I have an Interface named IMap that is shared in a dll file to create Addins based on that interface:
public interface IMap
{
object Map(object input);
}
I also have different Mappers (you can pass an input through them and they modify the output). All Mappers are derived from:
[XmlInclude(typeof(ConstMapper))]
[XmlInclude(typeof(FuncMapper))]
[XmlInclude(typeof(IdentMapper))]
[XmlInclude(typeof(NullMapper))]
[XmlInclude(typeof(RefMapper))]
[XmlInclude(typeof(VarMapper))]
[XmlInclude(typeof(TableMapper))]
[XmlInclude(typeof(AddinMapper))]
public class MapperBase:ComponentBase,IMap
{ public virtual object Map(object input) {
throw new NotImplementedException("Diese Methode muss überschrieben werden");
}
public override string ToString() {
return ShortDisplayName;
}
}
Just forget ComponentBase. It is not important for this...
Now i also have a AddinMapper. The main function of that mapper is to cast create MapperBase Object out of the IMap object:
And that is exactly that class I want to seralize including the properties of the Mapper Property (type IMap).
public class AddinMapper : MapperBase
{
private static MapperBase[] _mappers;
const string addinDirectory = #"Addin\Mappers\";
//Mappers from *.dll files are loaded here:
[XmlIgnore]
public static MapperBase[] Mappers
{
get
{
if (_mappers == null)
{
List<MapperBase> maps = new List<MapperBase>();
foreach (string dll in Directory.GetFiles(addinDirectory, "*.dll"))
{
if (Path.GetFileName(dll) != "IMap.dll")
{
var absolutePath = Path.Combine(Environment.CurrentDirectory, dll);
Assembly asm = Assembly.LoadFile(absolutePath);
foreach (Type type in asm.GetTypes().ToList().Where(p => p.GetInterface("IMap") != null))
{
maps.Add(new AddinMapper((IMap)Activator.CreateInstance(type)));
}
}
}
Mappers = maps.ToArray();
}
return _mappers;
}
set
{
_mappers = value;
}
}
IMap _base;
public string MapperString { get; set; }
[XmlIgnore()]
public IMap Mapper
{
get
{
if (_base == null)
{
Type type = null;
foreach (MapperBase mapperBase in Mappers)
{
if (mapperBase is AddinMapper && ((AddinMapper)mapperBase).Mapper.GetType().FullName == _mapperName)
{
type = (mapperBase as AddinMapper).Mapper.GetType();
break;
}
}
if (type != null)
{
XmlSerializer serializer = new XmlSerializer(type);
using (StringReader reader = new StringReader(MapperString))
{
Mapper = (IMap)serializer.Deserialize(reader);
}
}
}
return _base;
}
private set
{
_base = value;
StoreMapperString();
}
}
string _mapperName;
[System.ComponentModel.Browsable(false)]
public string MapperName
{
get
{
return _mapperName;
}
set
{
_mapperName = value;
}
}
public AddinMapper(IMap baseInterface) : this()
{
Mapper = baseInterface;
_mapperName = baseInterface.GetType().FullName;
}
public AddinMapper()
{
}
public override object Map(object input)
{
return Mapper.Map(input);
}
public override string ToString()
{
return Mapper.ToString();
}
private void StoreMapperString()
{
MemoryStream memstream = new MemoryStream();
XmlStore.SaveObject(memstream, Mapper);
using (StreamReader reader = new StreamReader(memstream))
{
memstream.Position = 0;
MapperString = reader.ReadToEnd();
}
}
}
An example for such a addin would be:
public class ReplaceMapper : IMap
{
public string StringToReplace { get; set; }
public string StringToInsert { get; set; }
public object Map(object input)
{
if (input is string)
{
input = (input as string).Replace(StringToReplace, StringToInsert);
}
return input;
}
}
And the Problem is I want to save the Settings like StringToReplace,... as xml
I ve solved my problem:
I really don t know why but take a look at this article: http://www.calvinirwin.net/2011/02/10/xmlserialization-deserialize-causes-xmlns-was-not-expected/
(if link is dead later)
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = elementName;
xRoot.IsNullable = true;
XmlSerializer ser = new XmlSerializer(typeof(MyObject), xRoot);
XmlReader xRdr = XmlReader.Create(new StringReader(xmlData));
MyObject tvd = (MyObject)ser.Deserialize(xRdr);
Now the important thing: It does not matter if you don t get an excption on serialization. You have to add the XmlRootAttribute on both ways: Serialisation and Deserialization.

Creating MTOM and Deserializing it

I have been using some code to create MTOM by using code from MSDN.
It seems that there is an error and I cannot understand where the problem lies as one of the users on the forum pointed out that there is an error.
The file (JPEG) data get corrupted after a de-serialization. The complete code is listed below.
public class Post_7cb0ff86_5fe1_4266_afac_bcb91eaca5ec
{
[DataContract()]
public partial class TestAttachment
{
private byte[] fileField;
private string filenameField;
[DataMember()]
public byte[] File
{
get
{
return this.fileField;
}
set
{
this.fileField = value;
}
}
[DataMember()]
public string Filename
{
get
{
return this.filenameField;
}
set
{
this.filenameField = value;
}
}
}
public static void Test()
{
string Filename = "Image.jpg";
byte[] file = File.ReadAllBytes(Filename);
TestAttachment Attachment = new TestAttachment();
Attachment.Filename = Filename;
Attachment.File = file;
MemoryStream MTOMInMemory = new MemoryStream();
XmlDictionaryWriter TW = XmlDictionaryWriter.CreateMtomWriter(MTOMInMemory, Encoding.UTF8, Int32.MaxValue, "");
DataContractSerializer DCS = new DataContractSerializer(Attachment.GetType());
DCS.WriteObject(TW, Attachment);
TW.Flush();
Console.WriteLine(Encoding.UTF8.GetString(MTOMInMemory.ToArray()));
var v = DeserializeMTOMMessage(Encoding.UTF8.GetString(MTOMInMemory.ToArray()));
File.WriteAllBytes(v.Filename,v.File);
}
public static TestAttachment DeserializeMTOMMessage(string MTOMMessage)
{
try
{
MemoryStream MTOMMessageInMemory = new MemoryStream(UTF8Encoding.UTF8.GetBytes(MTOMMessage));
XmlDictionaryReader TR = XmlDictionaryReader.CreateMtomReader(MTOMMessageInMemory, Encoding.UTF8, XmlDictionaryReaderQuotas.Max);
DataContractSerializer DCS = new DataContractSerializer(typeof(TestAttachment));
return (TestAttachment)DCS.ReadObject(TR);
}
catch
{
return null;
}
}
}
I would be grateful if someone can help me in pointing out where the problem is. I am new to XOP/MTOM and find it hard to track down where the error might be. Either serialization or de-serialization.
Thank you
There's a bug in your code.
Change your method call
MTOMInMemory.Position = 0;
DeserializeMTOMMessage(Encoding.UTF8.GetString(MTOMInMemory.ToArray()));
to
DeserializeMTOMMessage(MTOMInMemory.ToArray())
and the implementation to
public static TestAttachment DeserializeMTOMMessage(byte[] MTOMMessage)
{
try
{
MemoryStream MTOMMessageInMemory = new MemoryStream(MTOMMessage);
XmlDictionaryReader TR = XmlDictionaryReader.CreateMtomReader(MTOMMessageInMemory, Encoding.UTF8, XmlDictionaryReaderQuotas.Max);
DataContractSerializer DCS = new DataContractSerializer(typeof(TestAttachment));
return (TestAttachment)DCS.ReadObject(TR);
}
catch
{
return null;
}
}
what you've done was some double conversion from utf8 to byte array and vice versa, which ended up creating not the original byte array you were using

Categories