I seem to be getting some junk at the head of my serialized XML string. I have a simple extension method
public static string ToXML(this object This)
{
DataContractSerializer ser = new DataContractSerializer(This.GetType());
var settings = new XmlWriterSettings { Indent = true };
using (MemoryStream ms = new MemoryStream())
using (var w = XmlWriter.Create(ms, settings))
{
ser.WriteObject(w, This);
w.Flush();
return UTF8Encoding.Default.GetString(ms.ToArray());
}
}
and when I apply it to my object I get the string
<?xml version="1.0" encoding="utf-8"?>
<RootModelType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WeinCad.Data">
<MoineauPump xmlns:d2p1="http://schemas.datacontract.org/2004/07/Weingartner.Numerics">
<d2p1:Rotor>
<d2p1:Equidistance>0.0025</d2p1:Equidistance>
<d2p1:Lobes>2</d2p1:Lobes>
<d2p1:MajorRadius>0.04</d2p1:MajorRadius>
<d2p1:MinorRadius>0.03</d2p1:MinorRadius>
</d2p1:Rotor>
</MoineauPump>
</RootModelType>
Note the junk at the beginning. When I try to deserialize this
I get an error. If I copy paste the XML into my source minus
the junk prefix I can deserialize it. What is the junk text
and how can I remove it or handle it?
Note my deserialization code is
public static RootModelType Load(Stream data)
{
DataContractSerializer ser = new DataContractSerializer(typeof(RootModelType));
return (RootModelType)ser.ReadObject(data);
}
public static RootModelType Load(string data)
{
using(var stream = new MemoryStream(Encoding.UTF8.GetBytes(data))){
return Load(stream);
}
}
This fix seems to work
public static string ToXML(this object obj)
{
var settings = new XmlWriterSettings { Indent = true };
using (MemoryStream memoryStream = new MemoryStream())
using (StreamReader reader = new StreamReader(memoryStream))
using(XmlWriter writer = XmlWriter.Create(memoryStream, settings))
{
DataContractSerializer serializer =
new DataContractSerializer(obj.GetType());
serializer.WriteObject(writer, obj);
writer.Flush();
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}
Related
Recently upgraded a 3.5 project to 4.5. There is a chunk of data that we are serializing and storing in the database, but everytime a save occurs in the upgraded project, the XML formatting has changed, throwing errors, and I can't seem to figure out the core issue. There are 2 SO questions in particular that mention encoding changes, but I've tried switching to UTF8 (in a few different ways specified in the answers on those questions), without any success - with UTF8 I just got a mess of strange characters throughout the entire file.
The main issues that I can see occurring are:
A leading ? character is added to the XML (which I've come to find out is a valid character, but we aren't handling apparently)
Child nodes aren't being included with some of the nodes.
Here is our serialization method:
public static string SerializeXml<T>(T instance)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
MemoryStream memStream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(memStream, Encoding.Unicode);
serializer.Serialize(xmlWriter, instance);
memStream = (MemoryStream)xmlWriter.BaseStream;
return UnicodeEncoding.Unicode.GetString(memStream.ToArray()).Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", "");
}
and our deserialization method:
public static T DeserializeXml<T>(string xml)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
StringReader reader = new StringReader(xml);
return (T)xs.Deserialize(reader);
}
Any help would be appreciated, I am not too familiar with serialization or encoding. Just curious what may have changed with the upgrade to 4.5, or if there is something I need to take a closer look at.
If you want to Serialize to a String you need to use UTF16. If you want to Serialize with UTF8 you need to serialize to a byte[]. Strings in C# are UTF16 so in the code you posted I believe all your data is encoded with UTF16 but because you are omitting the Xml Declaration code assumes it is UTF8.
I would recommend using functions like this and not omitting the XmlDeclaration:
public static string SerializeXmlToString<T>(T instance)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.Unicode;
StringBuilder builder = new StringBuilder();
using (StringWriter writer = new StringWriter(builder))
using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings))
{
serializer.Serialize(xmlWriter, instance);
}
return builder.ToString();
}
public static byte[] SerializeXml<T>(T instance)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
using (MemoryStream memStream = new MemoryStream())
{
using (XmlWriter xmlWriter = XmlWriter.Create(memStream, settings))
{
serializer.Serialize(xmlWriter, instance);
}
return memStream.ToArray();
}
}
public static T DeserializeXml<T>(string data)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringReader reader = new StringReader(data))
{
return (T)serializer.Deserialize(reader);
}
}
public static T DeserializeXml<T>(byte[] bytes)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using(MemoryStream stream = new MemoryStream(bytes))
{
return (T)serializer.Deserialize(stream);
}
}
I am sending a request to a web service which requires a string containing XML, of which I have been giving an XSD.
I've ran xsd.exe and created a class based on this but am unsure of the best way to create the xml string to send, for example a stream, XMLDocument or some form of serialization.
UPDATE
I found this here
public static string XmlSerialize(object o)
{
using (var stringWriter = new StringWriter())
{
var settings = new XmlWriterSettings
{
Encoding = Encoding.GetEncoding(1252),
OmitXmlDeclaration = true
};
using (var writer = XmlWriter.Create(stringWriter, settings))
{
var xmlSerializer = new XmlSerializer(o.GetType());
xmlSerializer.Serialize(writer, o);
}
return stringWriter.ToString();
}
}
which lets me control the tag attribute.
What I am doing on several occasions is creating a class/struct to hold the data on the client-side program and serializing the data as a string. Then I make the web request and send it that XML string. Here is the code I use to serialize an object to XML:
public static string SerializeToString(object o)
{
string serialized = "";
System.Text.StringBuilder sb = new System.Text.StringBuilder();
//Serialize to memory stream
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(o.GetType());
System.IO.TextWriter w = new System.IO.StringWriter(sb);
ser.Serialize(w, o);
w.Close();
//Read to string
serialized = sb.ToString();
return serialized;
}
As long as all the contents of the object are serializable it will serialize any object.
Use Xstream framework to generate an xml string. Hope this helps!
Here's what I have done before:
private static string CreateXMLString(object o)
{
XmlSerializer serializer = new XmlSerializer(typeof(object));
var stringBuilder = new StringBuilder();
using (var writer = XmlWriter.Create(stringBuilder))
{
serializer.Serialize(writer, o);
}
return stringBuilder.ToString();
}
I had a quick question regarding the datacontractserializer. Maybe it's more of a stream question. I found a piece of code that writes the xml to a filestream. I basically don't want the file and just need the string output.
public static string DataContractSerializeObject<T>(T objectToSerialize)
{
var fs = new FileStream("test.xml", FileMode.OpenOrCreate);
var serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(fs, objectToSerialize);
fs.Close();
return fs.ToString();
}
fs.ToString() is obviously not what I'm looking for. What stream or writer etc, can I use just to return the proper string and not create a file? I did look at the XML the filestream created and it's exactly what I'm looking for. The XmlSerializer wrote the XML a bit strange and I prefer the output of the DataContractSerializer in this case. Can anyone point me in the right direction?
Something like this - put your output into a MemoryStream and then read that back in:
public static string DataContractSerializeObject<T>(T objectToSerialize)
{
using(MemoryStream memStm = new MemoryStream())
{
var serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(memStm, objectToSerialize);
memStm.Seek(0, SeekOrigin.Begin);
using(var streamReader = new StreamReader(memStm))
{
string result = streamReader.ReadToEnd();
return result;
}
}
}
Thanks to #xr280xr for pointing out my forgotten StringWriter disposal in the first draft.
/// <summary>
/// Converts this instance to XML.
/// </summary>
/// <returns>XML representing this instance.</returns>
public string ToXml()
{
var serializer = new DataContractSerializer(this.GetType());
using (var output = new StringWriter())
using (var writer = new XmlTextWriter(output) { Formatting = Formatting.Indented })
{
serializer.WriteObject(writer, this);
return output.GetStringBuilder().ToString();
}
}
And even easier:
var serializer = new DataContractSerializer(typeof(T));
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
serializer.WriteObject(writer, objectToSerialize);
writer.Flush();
return sb.ToString();
}
I suggest combining the methods given by Pat and marc_s:
public static string DataContractSerializeObject<T>(T objectToSerialize)
{
using (var output = new StringWriter())
using (var writer = new XmlTextWriter(output) {Formatting = Formatting.Indented})
{
new DataContractSerializer(typeof (T)).WriteObject(writer, objectToSerialize);
return output.GetStringBuilder().ToString();
}
}
A variant of #root's answer:
var serializer = new DataContractSerializer(typeof(T));
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
serializer.WriteObject(writer, objectToSerialize);
}
return sb.ToString();
I am writing common functions to serialize the given object and List<object> as follows
public string SerializeObject(Object pObject)// for given object
{
try
{
String XmlizedString = null;
MemoryStream memoryStream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(pObject));
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
xs.Serialize(xmlTextWriter, pObject);
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
return XmlizedString;
}
catch (Exception e) { System.Console.WriteLine(e); return null; }
}
public string SerializeObject(List<Object> pObject)// for given List<object>
{
try
{
String XmlizedString = null;
MemoryStream memoryStream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(pObject));
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
xs.Serialize(xmlTextWriter, pObject);
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
return XmlizedString;
}
catch (Exception e) { System.Console.WriteLine(e); return null; }
}
first one is working fine. If I pass any type, it is successfully returning xml string.
CORRECTION: Compilation error has occurred for second one (Error: cannot convert from List<MyType> to List<object>.
I rewrite the second one as follows which solves my problem. Now it is serializing the given List<generic types>.
private string SerializeObject<T>(T source)
{
MemoryStream memoryStream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(T));
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
xs.Serialize(xmlTextWriter, source);
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
string XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
return XmlizedString;
}
https://weblogs.asp.net/rajbk/Contents/Item/Display/345
The relevant code from the article:
private static string SerializeObject<T>(T source)
{
var serializer = new XmlSerializer(typeof(T));
using (var sw = new System.IO.StringWriter())
using (var writer = XmlWriter.Create(sw))
{
serializer.Serialize(writer, source);
return sw.ToString();
}
}
I have tried your two functions without much trouble. The only thing I changed was this line:
XmlSerializer xs = new XmlSerializer(typeof(pObject));
to this:
XmlSerializer xs = new XmlSerializer(pObject.GetType());
typeof() requires an actual type whereas GetType() returns the type of the object.
I encountered a problem with SOAP serialization and it would be great to find an answer. Here's a very simplified example:
public void Test()
{
StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb);
SoapReflectionImporter importer = new SoapReflectionImporter();
XmlTypeMapping map = importer.ImportTypeMapping(typeof(A));
XmlSerializer serializer = new XmlSerializer(map);
serializer.Serialize(writer, new A());
}
[Serializable]
public class A
{
public A()
{
BB = new B();
}
public int a;
public B BB;
}
[Serializable]
public class B
{
public int A1 { get; set; }
public int A2 { get; set; }
}
If I run method Test() then I get the following exception: System.InvalidOperationException: Token StartElement in state Epilog would result in an invalid XML document.
Would appreciate any help.
Use XmlWriter instead of StringWriter and do a writer.WriteStartElement("root");
This will work:
Stream s = new MemoryStream();
XmlWriter writer = new XmlTextWriter(s, Encoding.UTF8);
SoapReflectionImporter importer = new SoapReflectionImporter();
XmlTypeMapping map = importer.ImportTypeMapping(typeof(A));
XmlSerializer serializer = new XmlSerializer(map);
writer.WriteStartElement("root");
serializer.Serialize(writer, new A());
StreamReader sr = new StreamReader(s);
string data = sr.ReadToEnd();
Just a note,
The upper example will not work if the position of the stream is not set to the start of the stream. Like so:
Stream s = new MemoryStream();
XmlWriter writer = new XmlTextWriter(s, Encoding.UTF8);
SoapReflectionImporter importer = new SoapReflectionImporter();
XmlTypeMapping map = importer.ImportTypeMapping(typeof(A));
XmlSerializer serializer = new XmlSerializer(map);
writer.WriteStartElement("root");
serializer.Serialize(writer, new A());
s.Position = 0;
StreamReader sr = new StreamReader(s);
string data = sr.ReadToEnd();