Writing to an XML Document in Windows Phone 7 - c#

I'm attempting to write some data from an object to an XML document and am following a tutorial online, however I have run into a problem which I can't seem to fathom, the code I'm using to initiate the creation of the document isusing (XmlWriter writer = XmlWriter.Create("myData.xml")) and I'm getting an error with the "myData.xml", the errors I get are:
The best overload method match for 'System.Xml.XmlWriter.Create(System.Xml.XmlWriter)'
has some invalid arguments
Argument 1: cannot convert from 'string' to 'System.Xml.XmlWriter'
Is XmlWriter compatible with Windows Phone? And if not will I have to change huge amounts of code that writes to the file?
Edit: Here's my code
string output = SerializeToString<AppData>(rulesData);
using (XmlWriter writer = XmlWriter.Create(output))
{
writer.WriteStartDocument();
writer.WriteStartElement("myData");
writer.WriteElementString("Starting Cash", rulesData.myStartingCash);
writer.WriteElementString("Land on Go Data", rulesData.myLandOnGo);
writer.WriteElementString("Free Parking Data", rulesData.myFreeParking);
writer.WriteElementString("Full Circuit Data", rulesData.myFullCircuit);
writer.WriteElementString("Auction Data", rulesData.myAuction);
writer.Flush();
writer.WriteEndElement();
writer.WriteEndDocument();
}
Thanks! -Ryan

You can use this code:
public static void SerializeToStream<T>(Stream stream, object model)
{
var writer = XmlWriter.Create(stream);
var s = new XmlSerializer(typeof(T));
s.Serialize(writer, model);
}
public static string SerializeToString<T>(object model)
{
var xmlSer = new XmlSerializer(typeof(T));
using (var stream = new MemoryStream())
{
SerializeToStream<T>(stream, model);
var s = stream.ToArray();
return System.Text.Encoding.UTF8.GetString(s, 0, s.Length);
}
}
public static void SerializeToFile<T>(string filename, object model)
{
using (FileStream stream = File.Open(filename, FileMode.Create))
{
SerializeToStream<T>(stream, model);
}
}
Your code doesn't compile because you pass a string instead of a stream to XmlWriter
Usage:
string output = SerializeToString<ClassName>(instanceOfClass);

Related

Use XmlSerializer.CanDeserialize() when deserializing from string

I have a method that returns object from .xml file
(please don't mind resource usage and naming, it's just an example)
public static T FromXMLFile<T>(string filePath)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
FileStream fs = new FileStream(filePath, FileMode.Open);
XmlTextReader xmlTextReader = new XmlTextReader(fs);
if(xmlSerializer.CanDeserialize(xmlTextReader))
{
object tempObject = (T)xmlSerializer.Deserialize(xmlTextReader );
xmlTextReader.Close();
return (T)tempObject;
}
else
return default(T);
}
Now I would like to do the same but with with string instead of a file. I came up with something like this (again, simplified example)
public static T FromString<T>(string inputString)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
T result;
try
{
using (TextReader reader = new StringReader(inputString))
{
result = (T)serializer.Deserialize(reader);
}
return result;
}
catch //temporary solution, finally should stick to .CanDeserialize(xmlTextReader) usage
{
return default(T);
}
}
How would I use .CanDeserialize() in this case?
Rather than using the Deserialize(TextReader) overload, create an XmlReader from the TextReader, and use that XmlReader for both the Deserialize and CanDeserialize calls:
using (TextReader reader = new StringReader(inputString))
using (XmlReader xmlReader = XmlReader.Create(reader))
{
if (serializer.CanDeserialize(xmlReader))
{
result = (T)serializer.Deserialize(xmlReader);
}
}
This approach - with both read and write - also allows you to supply additional reader/writer settings for fine-grained control of the API.

XMLSerializer - issue with UTF-8 vs UTF-16 Code

I am trying to serialize a simple object (5 string properties) into XML to save to a DB Image field. Then I need to DeSerialize it back into a string later in the program.
However, I am getting some errors - caused by the XML being saved thinking it is in UTF-16 - however, when I load it from the DB back into a string - it thinks it is a UTF 8 String.
The error I get is
InnerException {"There is no Unicode byte order mark. Cannot switch to Unicode."} System.Exception {System.Xml.XmlException}
-- Message "There is an error in XML document (0, 0)." string
Is this happening because of the two different ways I save and load the string to/from the DB? On the save I am using a StringBuilder - but on the load from DB I am using just a String.
Thoughts?
Serialize and Save to DB
// Now Save the OBject XML to the Query Tables
var serializer = new XmlSerializer(ExportConfig.GetType());
StringBuilder StringResult = new StringBuilder();
using (var writer = XmlWriter.Create(StringResult))
{
serializer.Serialize(writer, ExportConfig);
}
//MessageBox.Show("XML : " + StringResult);
// Now Save to the Query
try
{
string UpdateSQL = "Update ZQryRpt "
+ " Set ExportConfig = " + TAGlobal.QuotedStr(StringResult.ToString())
+ " where QryId = " + TAGlobal.QuotedStr(((DataRowView)bindingSource_zQryRpt.Current).Row["QryID"].ToString())
;
ExecNonSelectSQL(UpdateSQL, uniConnection_Config);
}
catch (Exception Error)
{
MessageBox.Show("Error Setting ExportConfig: " + Error.Message);
}
Load from DB And Deserialize
byte[] binaryData = (byte[])((DataRowView)bindingSource_zQryRpt.Current).Row["ExportConfig"];
string XMLStored = System.Text.Encoding.UTF8.GetString(binaryData, 0, binaryData.Length);
if (XMLStored.Length > 0)
{
IIDExportObject ExportConfig = new IIDExportObject();
var serializer = new XmlSerializer(ExportConfig.GetType());
//StringBuilder StringResult = new StringBuilder(XMLStored);
// Load the XML from the Query into the StringBuilder
// Now we need to build a Stream from the String to use in the XMLReader
byte[] byteArray = Encoding.UTF8.GetBytes(XMLStored);
MemoryStream stream = new MemoryStream(byteArray);
using (var reader = XmlReader.Create(stream))
{
ExportConfig = (IIDExportObject)serializer.Deserialize(reader);
}
}
John - thank you very much for the comment! It allowed me to complete the code and find a solution.
As you noted - using a stream reader was the solution - but I could not read the first line because there was only one 'line' in my string. However, I could use the line
using (StreamReader sr = new StreamReader(stream, false))
Which allows me to read the stream and ignore the "Byte Order Mark Detection" set to false.
string XMLStored = MainFormRef.GetExportConfigForCurrentQuery();
if (XMLStored.Length > 0)
{
IIDExportObject ExportConfig = new IIDExportObject();
try
{
var serializer = new XmlSerializer(ExportConfig.GetType());
// Now we need to build a Stream from the String to use in the XMLReader
byte[] byteArray = Encoding.UTF8.GetBytes(XMLStored);
MemoryStream stream = new MemoryStream(byteArray);
// Now we need to use a StreamReader to get around UTF8 vs UTF16 issues
// A little cumbersome - but it works
using (StreamReader sr = new StreamReader(stream, false))
{
using (var reader = XmlReader.Create(sr))
{
ExportConfig = (IIDExportObject)serializer.Deserialize(reader);
}
}
}
catch
{
}
I am not sure this is the best solution - but it works. I will be curious to see if anyone else has a better way of dealing with this.
Thanks to G Bradley, I took his answer and generalized it a bit to make it a bit easier to call.
public static string SerializeToXmlString<T>(T objectToSerialize)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = false;
settings.Encoding = Encoding.UTF8;
StringBuilder builder = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(builder, settings))
{
serializer.Serialize(writer, objectToSerialize);
}
return builder.ToString();
}
public static T DeserializeFromXmlString<T>(string xmlString)
{
if (string.IsNullOrWhiteSpace(xmlString))
return default;
var serializer = new XmlSerializer(typeof(T));
byte[] byteArray = Encoding.UTF8.GetBytes(xmlString);
MemoryStream stream = new MemoryStream(byteArray);
using (StreamReader sr = new StreamReader(stream, false))
{
using (var reader = XmlReader.Create(sr))
{
return (T)serializer.Deserialize(reader);
}
}
}

Saving XDocument to file in PCL C#

I'm working within my PCL library and need to serialise a class and output to a file. I'm very short on space, so don't have the space for PCLStorage.
Currently I'm using this for the serialisation. IFilePath returns a file path from the non-PCL part.
IFilePath FilePath;
public void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) { return; }
try
{
using (var ms = new MemoryStream())
{
var xmlDocument = new XDocument();
using (var writer = xmlDocument.CreateWriter())
{
var serialize = new DataContractSerializer(typeof(T));
serialize.WriteObject(writer, serializableObject);
xmlDocument.Save(ms, SaveOptions.None);
}
}
}
catch (Exception ex)
{
//Log exception here
}
}
When I try to save, nothing is showing. I have a feeling it's because I'm not outputting the stream to a file, but I'm at a loss as how to do this.
You are trying to save to a file, an action which is specific for each platform.
PCLStorage is implementing this functionality for each platform and this is what you will have to do also if you can"t use it.
In you case what you have to do is to create the stream (in each platform) in your non pcl code and then pass it to your function which will look like this:
public void SerializeObject<T>(T serializableObject, Stream fileStream)
{
if (serializableObject == null) { return; }
try
{
var xmlDocument = new XDocument();
using (var writer = xmlDocument.CreateWriter())
{
var serialize = new DataContractSerializer(typeof(T));
serialize.WriteObject(writer, serializableObject);
xmlDocument.Save(fileStream, SaveOptions.None);
}
}
catch (Exception ex)
{
//Log exception here
}
}
more on pcl here.
Problem is that your variable ms in using (var ms = new MemoryStream()) is empty and does not point to any file location of which MemoryStream does not receive a filepath as argument. I propose you use a StreamWriter instead and pass the your FileStream to it. Example
Use your fileName to create a FileStream which inherits from the Stream class then replace the Memory stream with the newly created filestream like this.
using(FileStream stream = File.OpenWrite(fileName))
{
var xmlDocument = new XDocument();
using (var writer = xmlDocument.CreateWriter())
{
var serialize = new DataContractSerializer(typeof(T));
serialize.WriteObject(writer, serializableObject);
xmlDocument.Save(stream, SaveOptions.None);
}
}
Hope this helps.

unit testing a void method with StreamWriter as one of the parameters

I currently have a method like this
public void BusinessMethod(object value, StreamWriter sw)
{
//Calls a private method that converts the data in `value` to a custom formatted string variable `str`
string str = myPrivateMethod(value);
//write the string to stream
sw.Write(str);
}
I am trying to test this method using the approach mentioned here and have done exactly the same thing. However, my result string comes back as an empty string. I cannot change the method signature. How does one test a method like this? I am using Nunit for testing.
This is my test method
[Test]
public void My_Test()
{
MyPoco dto = new MyPoco ();
//set up the dto properties here
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
{
sut.BusinessMethod(dto, writer);
string result = Encoding.UTF8.GetString(stream.ToArray());
}
}
You need to Close/Flush/Dispose writer so it actually commits changes to stream:
using (var stream = new MemoryStream())
{
using (var writer = new StreamWriter(stream))
{
sut.BusinessMethod(dto, writer);
}
// moved outside of inner using to ensure writer stored content to stream
string result = Encoding.UTF8.GetString(stream.ToArray());
}

Why xmlreader can't read something that xmlwriter wrote?

I have the simplest code in the world,
using (XmlWriter writer = XmlWriter.Create(stringWriter))
{
writer.WriteStartDocument();
writer.WriteStartElement("Board");
writer.WriteAttributeString("Rows", mRows.ToString());
writer.WriteAttributeString("Columns", mColumns.ToString());
writer.WriteEndElement();
writer.WriteEndDocument();
}
TextWriter writer1 = new StreamWriter(path);
writer1.Write(stringWriter.toString());
writer1.Close();
Then i write it to a txt file that looks like this:
<?xml version="1.0" encoding="utf-16"?>
<Board Rows="30" Columns="50">
</Board>
Then i do the following :
FileStream str = new FileStream(s.FileName, FileMode.Open);
using(XmlReader reader = XmlReader.Create(stream))
{
reader.Read();
}
And it throws an exception :
"There is no Unicode byte order mark. Cannot switch to Unicode."
I googled the exception and found several workarounds, but i don't understand why i need a work around, i just want to read the xml i wrote.
Can some one please explain what exactly the problem is ?
Should i write something differently in the xml ?
What is the simplest solution to this ?
You're probably not writing to a unicode file which File.WriteAllText or a vanilla FileStream does not do.
Instead use File.OpenWrite or FileStream combined with the StreamWriter(Stream steam, Encoding encoding) constructor to specify unicode.
Sample:
var path = #"C:\Dev\sample.xml";
string xml;
var mRows = 30;
var mColumns = 50;
var options = new XmlWriterSettings { Indent = true };
using (var stringWriter = new StringWriter())
{
using (var writer = XmlWriter.Create(stringWriter, options))
{
writer.WriteStartDocument();
writer.WriteStartElement("Board");
writer.WriteAttributeString("Rows", mRows.ToString());
writer.WriteAttributeString("Columns", mColumns.ToString());
writer.WriteEndElement();
writer.WriteEndDocument();
}
xml = stringWriter.ToString();
}
if(File.Exists(path))
File.Delete(path);
using(var stream = File.OpenWrite(path))
using(var writer = new StreamWriter(stream, Encoding.Unicode))
{
writer.Write(xml);
}
Console.Write(xml);
using(var stream = File.OpenRead(path))
using(var reader = XmlReader.Create(stream))
{
reader.Read();
}
File.Delete(path);

Categories