How to serialize/deserialize PictureBox - c#

[Serializable]
class GameObject : PictureBox
{
public bool Solid;
public bool Selected;
}
Is there any way to serialize BackColor, Size, Location etc...?

For temporary small type of objects I prefer to use structures, although you can use classes as per your needs. You can serialize and de-serialize objects using these helper methods.
public static string Serialize<T>(T objectToSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringWriter textWriter = new StringWriter();
xmlSerializer.Serialize(textWriter, objectToSerialize);
return textWriter.ToString();
}
public static T Deserialize<T>(string stringToDeserialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringReader textReader = new StringReader(stringToDeserialize);
return (T)xmlSerializer.Deserialize(textReader);
}
How to Serialize object-to-string:
MyStructure myObject = GetPictureBoxObject();
string pbSerializedString = Serialize<MyStructure>(myObject);
How to DeSerialize string-to-object:
string str = GetStringToDeserialize();
MyStructure myObject = Deserialize<MyStructure>(str);

Related

How to serialize a c# object with polymorphism to a soapmessage with overriden soapattributes, similar to XmlAttributeOverrides?

I have a dynamically created type, so I can't change it's implementation. I can't apply solutions like
[SoapInclude()]
Imagine if I had such classes:
public class BaseClass{}
public class DerivedClass:BaseClass{}
public class AnotherDerivedClass:BaseClass{}
public class RequestClass
{
public BaseClass item{get;set;}
}
If we try to just simply serialize we get the exception that DerivedClass was not found, so we have to override the xmlattributes.
I have managed to override my Type and serialize it with XmlAttributeOverrides like so:
var requestObject = new RequestClass() {item = new DerivedClass()};
XmlAttributes attrs = new XmlAttributes();
XmlElementAttribute attr = new XmlElementAttribute
{
ElementName = "DerivedClass",
Type = typeof(DerivedClass)
};
attrs.XmlElements.Add(attr);
XmlAttributeOverrides attoverrides = new XmlAttributeOverrides();
attoverrides.Add(typeof(RequestClass), "item", attrs);
XmlSerializer sr = new XmlSerializer(typeof(RequestClass), attoverrides);
StringWriter writer = new StringWriter();
sr.Serialize(writer, requestObject);
var xml = writer.ToString();
Now the above works, but what I want is to serialize my object as a soap-message. I have found similar classes to those above Like SoapAttributeOverrides and I've tried to override it with those classes and it doesn't seem to work. I've tried it like :
var requestObject = new RequestClass(){item = new DerivedClass()};
SoapAttributeOverrides ovr = new SoapAttributeOverrides();
SoapAttributes soapAtts = new SoapAttributes();
SoapElementAttribute element = new SoapElementAttribute();
element.ElementName = "DerivedClass";
ovr.Add(typeof(RequestClass), "item", soapAtts);
var sr = new XmlSerializer(new SoapReflectionImporter(ovr).ImportTypeMapping(typeof(RequestClass)));
StringWriter writer = new StringWriter();
sr.Serialize(writer, requestObject);
var xml = writer.ToString();
writer.Close();
I again get the exception DerivedClass was not found. How can I give the SoapElementAttribute a type similar to XmlElementAttribute.Type so that serialization can be made to support polymorphism for BaseClass via overrides?
SOAP-encoded XML serialization in .Net supports polymorphism via an included type mechanism. In order to add included types to a SoapReflectionImporter in runtime, use either:
SoapReflectionImporter.IncludeType(Type)
SoapReflectionImporter.IncludeTypes(ICustomAttributeProvider).
Thus you can manufacture your XmlSerializer as follows:
public static XmlSerializer RequestClassSerializer { get; }
= CreateSoapSerializerWithBaseClassIncludedTypes(typeof(RequestClass), typeof(DerivedClass), typeof(AnotherDerivedClass));
static XmlSerializer CreateSoapSerializerWithBaseClassIncludedTypes(Type rootType, params Type [] includedTypes)
{
var importer = new SoapReflectionImporter();
foreach (var type in includedTypes)
importer.IncludeType(type);
return new XmlSerializer(importer.ImportTypeMapping(rootType));
}
Then introduce the following extension method:
public static partial class XmlSerializationHelper
{
public static string GetSoapXml<T>(this T obj, XName wrapperName, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
xmlWriter.WriteStartElement(wrapperName.LocalName, wrapperName.NamespaceName);
(serializer ?? GetDefaultSoapSerializer(obj.GetType())).Serialize(xmlWriter, obj);
xmlWriter.WriteEndElement();
}
return textWriter.ToString();
}
}
static readonly Dictionary<Type, XmlSerializer> cache = new Dictionary<Type, XmlSerializer>();
public static XmlSerializer GetDefaultSoapSerializer(Type type)
{
lock(cache)
{
if (cache.TryGetValue(type, out var serializer))
return serializer;
return cache[type] = new XmlSerializer(new SoapReflectionImporter().ImportTypeMapping(type));
}
}
}
And you will be able to serialize your requestObject as follows:
var requestObject = new RequestClass(){item = new DerivedClass()};
var xml = requestObject.GetSoapXml("wrapper", RequestClassSerializer);
Notes:
To avoid a severe memory leak you should statically cache any XmlSerializer not created with the XmlSerializer(Type) or XmlSerializer(Type, String) constructors. For why, see the documentation and also Memory Leak using StreamReader and XmlSerializer.
If you are dynamically generating families of types you may need to cache their serializers in a static dictionary protected by lock statements.
As explained in Extension method to serialize generic objects as a SOAP formatted stream and InvalidOperationException while SOAP serialization of complex type you need to manually write an envelope or other wrapper element before serializing directly to XML using a SOAP XML serializer.
If for some reason you just want the SOAP XML body as a series of XML fragments, you can do:
public static string GetSoapBodyXml<T>(this T obj, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true, ConformanceLevel = ConformanceLevel.Fragment }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
xmlWriter.WriteWhitespace(""); // Hack to prevent an error about WriteStartDocument getting called for ConformanceLevel.Fragment
(serializer ?? GetDefaultSoapSerializer(obj.GetType())).Serialize(xmlWriter, obj);
}
return textWriter.ToString();
}
}
Demo fiddle here.

ignore xml-attribut when deserialising [duplicate]

Can I make XmlSerializer ignore the namespace (xmlns attribute) on deserialization so that it doesn't matter if the attribute is added or not or even if the attribute is bogus? I know that the source will always be trusted so I don't care about the xmlns attribute.
Yes, you can tell the XmlSerializer to ignore namespaces during de-serialization.
Define an XmlTextReader that ignores namespaces. Like so:
// helper class to ignore namespaces when de-serializing
public class NamespaceIgnorantXmlTextReader : XmlTextReader
{
public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader): base(reader) { }
public override string NamespaceURI
{
get { return ""; }
}
}
// helper class to omit XML decl at start of document when serializing
public class XTWFND : XmlTextWriter {
public XTWFND (System.IO.TextWriter w) : base(w) { Formatting= System.Xml.Formatting.Indented;}
public override void WriteStartDocument () { }
}
Here's an example of how you would de-serialize using that TextReader:
public class MyType1
{
public string Label
{
set { _Label= value; }
get { return _Label; }
}
private int _Epoch;
public int Epoch
{
set { _Epoch= value; }
get { return _Epoch; }
}
}
String RawXml_WithNamespaces = #"
<MyType1 xmlns='urn:booboo-dee-doo'>
<Label>This document has namespaces on its elements</Label>
<Epoch xmlns='urn:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'>0</Epoch>
</MyType1>";
System.IO.StringReader sr;
sr= new System.IO.StringReader(RawXml_WithNamespaces);
var s1 = new XmlSerializer(typeof(MyType1));
var o1= (MyType1) s1.Deserialize(new NamespaceIgnorantXmlTextReader(sr));
System.Console.WriteLine("\n\nDe-serialized, then serialized again:\n");
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("urn", "booboo-dee-doo");
s1.Serialize(new XTWFND(System.Console.Out), o1, ns);
Console.WriteLine("\n\n");
The result is like so:
<MyType1>
<Label>This document has namespaces on its elements</Label>
<Epoch>0</Epoch>
</MyType1>
If you expect no namespace, but the input has namespaces, then you can set
Namespaces = false
on your XmlTextReader.
Exdended Wolfgang Grinfeld answer (w/o exception handling):
public static Message Convert(XmlDocument doc)
{
Message obj;
using (TextReader textReader = new StringReader(doc.OuterXml))
{
using (XmlTextReader reader = new XmlTextReader(textReader))
{
reader.Namespaces = false;
XmlSerializer serializer = new XmlSerializer(typeof(Message));
obj = (Message)serializer.Deserialize(reader);
}
}
return obj;
}
Solved this by using XmlSerializer Deserialize to read from xml instead from stream. This way before xml is Deserialized, using Regex to remove xsi:type from the xml. Was doing this is Portable Class Library for Cross Platform, so did not had many other options :(. After this the deserialization seems to work fine.
Following code can help,
public static TClass Deserialize<TClass>(string xml) where TClass : class, new()
{
var tClass = new TClass();
xml = RemoveTypeTagFromXml(xml);
var xmlSerializer = new XmlSerializer(typeof(TClass));
using (TextReader textReader = new StringReader(xml))
{
tClass = (TClass)xmlSerializer.Deserialize(textReader);
}
return tClass;
}
public static string RemoveTypeTagFromXml(string xml)
{
if (!string.IsNullOrEmpty(xml) && xml.Contains("xsi:type"))
{
xml = Regex.Replace(xml, #"\s+xsi:type=""\w+""", "");
}
return xml;
}
Why try to make the XmlSerializer forget how XML works? It's a fact of XML that two elements with the same name but different namespaces are different elements.
If you want to process XML that has no namespaces, then you should pre-process it to remove the namespaces, and then pass it to the serializer.

How to inject an object to Serialize to File?

The problem is simple, I want to create a method to serialize and another to open it by passing any object structure. I have the following which is what I believed should work but, guess what, it doesn't:
List<string> list = new List<string>();
list.Add("aaa");
list.Add("bbb");
FileSystem.SerializeToFile(list, "");
List<string> anotherList = FileSystem.OpenSerialized(typeof(List<string>), "");
public class FileSystem
{
public static void SerializeToFile(object toSerialize, string fileName)
{
XmlSerializer writer = new XmlSerializer(typeof(object));
StreamWriter file = new StreamWriter(fileName);
writer.Serialize(file, toSerialize);
file.Close();
}
public static object OpenSerialized(Type type, string fileName)
{
XmlSerializer serializer = new XmlSerializer(typeof(object));
StreamReader reader = new StreamReader(fileName);
object something = serializer.Deserialize(reader);
return something;
}
}
The serializer’s constructor requires a reference to the type of object it should work, slightly modified your code to fit to requirement.
public class FileSystem
{
public static void SerializeToFile<T>(T toSerialize, string fileName)
{
XmlSerializer writer = new XmlSerializer(typeof(T));
StreamWriter file = new StreamWriter(fileName);
writer.Serialize(file, toSerialize);
file.Close();
}
public static T OpenSerialized<T>(string fileName)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StreamReader reader = new StreamReader(fileName);
object something = serializer.Deserialize(reader);
return (T)something;
}
}
and now we can use this as
List<string> list = new List<string>();
list.Add("aaa");
list.Add("bbb");
FileSystem.SerializeToFile(list, #"d:\test.txt");
List<string> anotherList = FileSystem.OpenSerialized<List<string>>(#"d:\test.txt");

Understanding System.Xml.Serialization.XmlIgnoreAttribute with base classes

I have two classes, shown below:
[Serializable]
[XmlInclude(typeof(SomeDerived))]
public class SomeBase
{
public string SomeProperty { get; set; }
}
public class SomeDerived : SomeBase
{
[XmlIgnore]
public new string SomeProperty { get; set; }
}
When I serialize and instance of SomeDerived I don't expect to see a value for SomeProperty. However, I do. I've tried other approaches such as having SomeProperty declared as virtual in SomeBase and overriding it in SomeDerived. Still I see it in a serialized instance of SomeDerived.
Can anyone explain what is going on with the XmlIgnoreAttribute?
For completeness, my deserialization code is below
class Program
{
static void Main(string[] args)
{
SomeDerived someDerived = new SomeDerived { SomeProperty = "foo" };
XmlSerializer ser = new XmlSerializer(typeof(SomeBase));
MemoryStream memStream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(memStream, Encoding.Default);
ser.Serialize(memStream, someDerived);
xmlWriter.Close();
memStream.Close();
string xml = Encoding.Default.GetString(memStream.GetBuffer());
Console.WriteLine(xml);
Console.ReadLine();
}
}
Edit
I get the same behaviour if I change the serializer declaration to new XmlSerializer(typeof(SomeDerived)).
Try this out. It uses the override on the XmlSerializer constructor to pass in some serialization overrides:
SomeDerived someDerived = new SomeDerived { SomeProperty = "foo" };
// Create the XmlAttributeOverrides and XmlAttributes objects.
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
/* Use the XmlIgnore to instruct the XmlSerializer to ignore
the GroupName instead. */
attrs = new XmlAttributes();
attrs.XmlIgnore = true;
overrides.Add(typeof(SomeBase), "SomeProperty", attrs);
XmlSerializer ser = new XmlSerializer(typeof(SomeBase), overrides);
MemoryStream memStream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(memStream, Encoding.Default);
ser.Serialize(memStream, someDerived);
xmlWriter.Close();
memStream.Close();
string xml = Encoding.Default.GetString(memStream.GetBuffer());

Can I Serialize XML straight to a string instead of a Stream with C#?

This example uses a StringWriter to hold the serialized data, then calling ToString() gives the actual string value:
Person john = new Person();
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));
StringWriter stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, john);
string serializedXML = stringWriter.ToString();
Is there any easier/Cleaner way to do this? All of the Serialize() overloads seem to use a Stream or Writer.
UPDATE: Asked a similar question about serializing an IEnumerable via an Extension Method .
Fun with extension methods...
var ret = john.ToXmlString()
public static class XmlTools
{
public static string ToXmlString<T>(this T input)
{
using (var writer = new StringWriter())
{
input.ToXml(writer);
return writer.ToString();
}
}
public static void ToXml<T>(this T objectToSerialize, Stream stream)
{
new XmlSerializer(typeof(T)).Serialize(stream, objectToSerialize);
}
public static void ToXml<T>(this T objectToSerialize, StringWriter writer)
{
new XmlSerializer(typeof(T)).Serialize(writer, objectToSerialize);
}
}
More or less your same solution, just using an extension method:
static class XmlExtensions {
// serialize an object to an XML string
public static string ToXml(this object obj) {
// remove the default namespaces
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
// serialize to string
XmlSerializer xs = new XmlSerializer(obj.GetType());
StringWriter sw = new StringWriter();
xs.Serialize(sw, obj, ns);
return sw.GetStringBuilder().ToString();
}
}
[XmlType("Element")]
public class Element {
[XmlAttribute("name")]
public string name;
}
class Program {
static void Main(string[] args) {
Element el = new Element();
el.name = "test";
Console.WriteLine(el.ToXml());
}
}
I created this helper method, but I haven't tested it yet. Updated the code per orsogufo's comments (twice):
private string ConvertObjectToXml(object objectToSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(objectToSerialize.GetType());
StringWriter stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, objectToSerialize);
return stringWriter.ToString();
}
Seems like no body actually answered his question, which is no, there is no way to generate an XML string without using a stream or writer object.

Categories