XmlSerializer Deserialize fails in release mode - c#

This is pretty odd. I have a configuration file which is well formed XML. I create a stream from the file and serialize it using what seems to be pretty typical code:
TextWriter tw = new StreamWriter(tempFile);
I use a serializer created as follows:
XmlSerializer ConfigSettingSerializer = new XmlSerializer(typeof(ConfigSettings));
Where ConfigSettings is just a container class containing string variables and values.
I then take the serialized stream and stash it away as a configuration using the ConfigurationManager class and AppSettings. I then retrieve the serialized data from appSettings and attempt to convert the stream back to the original class:
string configXml = ConfigurationManager.AppSettings[Id];
using (StringReader reader = new StringReader(configXml))
{
retVal = (ConfigSettings)MVHelper.ConfigSettingSerializer.Deserialize(reader);
}
This all works perfectly well until I switch from Debug to Release, when I get an error on the Deserialize call about invalid XML, complaining about the very last character in the document: There is an error in XML document (92, 18). The inner exception is: "Data at the root level is invalid. Line 92, position 18". The document is identical to the one generated in debug mode, and it renders fine in any browser. My guess is that there maybe something else going on and that the real error is somehow being masked, but so far I don't see it. Any advice would be greatly appreciated.
Thanks,
Gary

Load the XML file in a hex editor or other binary editor and check for unprintable characters like an encoding preamble.

Related

Error deserializing XML exported from BMFont tool

I am trying to use the following example: http://www.faqstackoverflow.com/answered/using-a-bmp-image-as-font-in-monogame
The concept seems sound. I'm using a .fnt generated by the suggested tool. It looks properly formatted and makes sense based on the [Serialization] used in the classes.
However, Every time I run the code I get this error: "An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: There is an error in XML document (1, 1)."
I have looked feverishly around StackExchange and google, and tried many things before coming here and posting my question. I have many of the messy leavings of those attempts still in the comments posted below inside the FontLoader class I am modifying to try to fix the issue. No matter how it is sliced, it gives the same error, or worse.
public class FontLoader
{
public static FontFile Load(String filename)
{
/* XmlSerializer deserializer = new XmlSerializer(typeof(FontFile));
TextReader textReader = new StreamReader(Encoding.UTF8.GetBytes(filename).ToString());
FontFile file = (FontFile)deserializer.Deserialize(textReader);
textReader.Close();
return file;*/
byte[] bytes = Encoding.UTF8.GetBytes(System.IO.File.ReadAllText(filename));
FontFile myInstance = null;
using (MemoryStream memStream = new MemoryStream(bytes))
{
XmlSerializer tokenSerializer = new XmlSerializer(typeof(FontFile));
myInstance = (FontFile)tokenSerializer.Deserialize(memStream);
Console.WriteLine(myInstance);
return myInstance;
}
/*
XmlSerializer deserializer = new XmlSerializer(typeof(FontFile));
TextReader textReader = new StreamReader(filename);
FontFile file = (FontFile)deserializer.Deserialize(textReader);
textReader.Close();
return file;*/
/* var xml = System.IO.File.ReadAllText(filename);
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
XmlSerializer serializer = new XmlSerializer(typeof(FontFile));
FontFile file = (FontFile)serializer.Deserialize(stream);
return file;
}*/
/* var writer = new StringWriter();
var serializer = new XmlSerializer((filename.GetType()));
serializer.Serialize(writer, filename);
string xml = writer.ToString();
return xml;*/
}
}
The font I'm using is Arial, as a test, so it should be ok to use. It starts out with these lines:
info face="Arial" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0
common lineHeight=32 base=26 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0
page id=0 file="arial_0.png"
chars count=191
char id=32 x=155 y=75 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
And then contineus with many "char" lines that have identical structure, followed by the kernings line, and then a bunce of "kerning" lines as below with identical structure to one another:
kernings count=91
kerning first=32 second=65 amount=-2
If it ends up being something wrong with the serialization, I apologize for positing, but I am not seeing it. Please let me know if anyone has a solution. Thank you.
The issue is actually obvious from your original question, but like you I overlooked the problem at first.
After you sent me the .fnt file I spotted the issue almost immediately because I compared it to one I exported earlier. The problem is that you've exported the file in the wrong format. As you said in your question, your file looks like this:
info face="Arial" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0
common lineHeight=32 base=26 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0
page id=0 file="arial_0.png"
chars count=191
char id=32 x=155 y=75 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
But it should look more like this:
<?xml version="1.0"?>
<font>
<info face="Arial" size="32" bold="1" italic="0" charset="" unicode="1" stretchH="100" smooth="1" aa="1" padding="0,0,0,0" spacing="1,1" outline="1"/>
<common lineHeight="32" base="26" scaleW="256" scaleH="256" pages="1" packed="0" alphaChnl="1" redChnl="0" greenChnl="0" blueChnl="0"/>
<pages>
<page id="0" file="arial_0.png" />
</pages>
<chars count="191">
Once you compare them side by side the difference is obvious. The first file is plain text and the second file is XML. It happens to the best of us :)
Anyway, to fix it you just need to set the file format to XML in the BMFont tool.
Click Options
Click Export Options
Click the XML radio button near the bottom of the dialog
Then export your file again.
A few things have changed since that answer you're referring to was written. Rather than writing it yourself you can use the MonoGame.Extended library to do exactly what you're trying to do. I wrote a detailed blog post about it a while back.
The first thing you'll need to do is install the MonoGame.Extended NuGet package. Run the following command in the Package Manager Console.
Install-Package MonoGame.Extended -Pre
Once it's installed you'll have a couple of DLLs in your packages folder. One of them will need to be referenced by the MonoGame Pipeline tool. The easiest way to do that is to edit your Content.mgcb file manually in a text editor. Add a reference line like this, but be sure to match the current version.
#-------------------------------- References --------------------------------#
/reference:..\..\packages\MonoGame.Extended.0.3.44-alpha\lib\MonoGame.Extended.Content.Pipeline.dll
Lastly, you can add your font file and texture to the MonoGame Pipeline tool and load like any other content.
_bitmapFont = Content.Load<BitmapFont>("my-font");
Then draw it using a sprite batch
_spriteBatch.Begin();
_spriteBatch.DrawString(_bitmapFont, "Hello World", new Vector2(100, 200), Color.Red);
_spriteBatch.End();
If you really do want to write it yourself you can look at the implementation from MonoGame.Extended as it's open source.

ReadXml from a Resource - Explanation

I've been working on a project (C#) and part of it was filling a data grid with an embedded xml file.
Although I've now found a way to make this work, i am still confused as to to theory behind it. And I'd like to stop and make sure i fully understand it before i continue with this project.
The code that i have working currently is;
XmlDataDocument myXML = new XmlDataDocument();
StringReader mytempXML = (new StringReader(BasicTest.Properties.Resources.myxml));
myXML.DataSet.ReadXml(mytempXML);
What is confusing to me is that before this solution, I was trying the below;
myXML.DataSet.ReadXml(BasicTest.Properties.Resources.myxml);
and it wasn't working. However using the full file path (like below) was working.
myXML.DataSet.ReadXml("C:/..etc../myxml.xml");
The Question I have is: why is a StringReader required for the ReadXml method if you're reading from a resource, but using a full file path works without?
If anyone could provide an explanation, that would be great.
Thanks.
This is because the ReadXml method takes a string. That string must be the name of a file. It cannot be XML. If you pass it a string that is XML, it will think that is the name of the file! It doesn't have the smarts to look at the string and ask "Is this string XML, or is it a file name?" and figure that out.
// Summary:
// Reads XML schema and data into the System.Data.DataSet using the specified
// file.
//
// Parameters:
// fileName:
// The filename (including the path) from which to read.
public XmlReadMode ReadXml(string fileName);
By wrapping the XML in a stringreader or a stream or something, you are calling a different overload, that expects XML instead of a file name.

Insert Object data to local xml file

I found this great tutorial for loading XML using XLINQ (LINQ to XML).
http://www.codearsenal.net/2012/07/c-sharp-load-xml-using-xlinq.html
It helped me a lot and I got the job done with it.
The only change I made was where he had this line:
from e in XDocument.Load(#"..\..\Employees.xml").Root.Elements("employee")
I write it like this:
from el in XDocument.Load("XML_Files/Employees.xml").Root.Elements("employee")
I had to change the path like this to access a local xml file found right inside my Visual Studio project.
But now I need to save the data back to the file in my project solution. Again, my xml file is located inside my C# project. It's not on the desktop or anything, it is a file added to the project solution.
I can't seem to find any good resources for how to do this task. Does anyone know a good tutorial, or code, a reference to start?
I am inserting a list of objects into the xml files. The objects have basic data type properties, except for one of the object properties, which is a List of doubles.
Can anyone advise a good tutorial or link? Or even a generic code sample?
I'd like to keep this function as basic as possible.
Please help.
------------------ UPDATE ------------------
I actually got this kind of working now. The below code does what I need EXCEPT that it won't write the data to my local file in the Visual Studio project. It will gladly write the data to a test file I created on my desktop, however.
Does anyone know why this is??
//create the serialiser to create the xml
XmlSerializer serialiser = new XmlSerializer(typeof(List<Student>));
// Create the TextWriter for the serialiser to use
TextWriter Filestream = new StreamWriter(#"C:\\Users\\MyName\\Desktop\\output.xml");
//write to the file
serialiser.Serialize(Filestream, employees);
// Close the file
Filestream.Close();
-------- UPDATE ---------
Okay, figured it out.
This code works:
public void WriteXML()
{
//create the serialiser to create the xml
XmlSerializer serialiser = new XmlSerializer(typeof(List<Student>));
// Create the TextWriter for the serialiser to use
TextWriter Filestream = new StreamWriter(#"XML_Files\Employees.xml");
//write to the file
serialiser.Serialize(Filestream, employees);
// Close the file
Filestream.Close();
}
The data is inserted to the xml file, but it does not show in Visual Studio. But when I checked here:
C:\Users\Me\Desktop\MyProject\MyProject\bin\Debug\XML_Files
The file is overwritten.
Also, when I reload the data from the application again, the new entries come up.
The problem is in line:
TextWriter Filestream = new StreamWriter(#"C:\\Users\\MyName\\Desktop\\output.xml");
Change it to one of following:
TextWriter Filestream = new StreamWriter("C:\\Users\\MyName\\Desktop\\output.xml");
TextWriter Filestream = new StreamWriter(#"C:\Users\MyName\Desktop\output.xml");
Simply remove the "#", OR use single slashes:

Correcting Encoding in a large Xml File

I'm importing data from XML files containing this type of content:
<FirstName>™MšR</FirstName><MiddleName/><LastName>HšNER™Z</LastName>
The XML is loaded via:
XmlDocument doc = new XmlDocument();
try
{
doc.Load(fullFilePath);
}
When I execute this code with the data contained on top I get an exception about an illegal character. I understand that part just fine.
I'm not sure which encoding this is or how to solve this problem. Is there a way I can change the encoding of the XmlDocument or another method to make sure the above content is parsed correctly?
Update: I do not have any encoding declaration or <?xml in this document.
I've seen some links say to add it dynamically? Is this UTF-16 encoding?
It appears that:
The name was ÖMÜR HÜNERÖZ (or possibly ÔMÜR HÜNERÔZ or ÕMÜR HÜNERÕZ; I don't know what language that is).
The XML file was encoded using the DOS "OEM" code page, probably 437 or 850.
But it was decoded using windows-1252 (the "ANSI" code page).
If you look at the file with a hex editor (HXD or Visual Studio, for instance), what exactly do you see?
Is every character from the string you posted represented by a single byte? Does the file have a byte-order mark (a bunch of non-printable bytes at the start of the file)?
The ™ and š seem to indicate that something went pretty wrong with encoding/conversion along the way, but let's see... I guess they both correspond with a vowel (O-M-A-R H-A-NER-O-Z, maybe?), but I haven't figured out yet how they ended up looking like this...
Edit: dan04 hit the nail on the head. ™ in cp-1252 has hex value 99, and š is 9a. In cp-437 and cp-850, hex 99 represents Ö, and 9a Ü.
The fix is simple: just specify this encoding when opening your XML file:
XmlDocument doc = new XmlDocument();
using (var reader = new StreamReader(fileName, Encoding.GetEncoding(437)))
{
doc.Load(reader);
}
From here:
Encoding encoding;
using (var stream = new MemoryStream(bytes))
{
using (var xmlreader = new XmlTextReader(stream))
{
xmlreader.MoveToContent();
encoding = xmlreader.Encoding;
}
}
You might want to take a look at this: How to best detect encoding in XML file?
For actual reading you can use StreamReader to take care of BOM(Byte order mark):
string xml;
using (var reader = new StreamReader("FilePath", true))
{ // ↑
xml= reader.ReadToEnd(); // detectEncodingFromByteOrderMarks
}
Edit: Removed the encoding parameter. StreamReader will detect the encoding of a file if the file contains a BOM. If it does not it will default to UTF8.
Edit 2: Detecting Text Encoding for StreamReader
Obviously you provided a fragment of the XML document since it's missing a root element, so I'll assume that was your intention. Is there an xml processing instruction at the top like <?xml version="1.0" encoding="UTF-8" ?>?

Invalid Assembly XML File

I am trying to read the XML Documentation file (C#) using this ocde -
Type classType = typeof(Point);
string documentationFileLocation = classType.Assembly.CodeBase;
if ( !string.IsNullOrEmpty(documentationFileLocation) && documentationFileLocation.StartsWith("file:///") )
{
documentationFileLocation = documentationFileLocation.Replace(".exe",".xml");
documentationFileLocation = documentationFileLocation.Replace("file:///","");
if(File.Exists(documentationFileLocation))
{
XElement document = XElement.Load(documentationFileLocation);
// Some Code Logic Here using LINQ
}
else
{
Console.WriteLine("Please Go to Project Properties->Build and check 'XML Documentation file'");
I have a LINQ Query after XElement document = XElement.Load(sr) which dosen`t work,
So I put a breakpoint in the LINQ Query and I am getting this error -
XmlException - Data at the root level is invalid. Line 1, position 1.
How I can fix it?
Edit:Changed the code a little - just deleted StreamReader
Well, it sounds like it simply isn't a valid XML file.
If you print out the result of sr.ReadToEnd() instead of calling XElement.Load, what does it look like? If you try to load the file into an XML editor, what happens?
Btw, it's better to use a using statement than calling Dispose explicitly: with your current code, the StreamReader isn't disposed if Load throws an exception.
Finally, is there any reason you're not just using XElement.Load(documentationFileLocation)?
Have you tried XDocument.Load() instead of using XElement? If the file begins with an XML declaration <?xml ..., you might get this error when trying to load an element from it.
Edit: the file you pasted on pastebin has no encoding specified. Can you try to open this file in notepad and re-save it as ANSI, the see if it loads? Just to make sure that we don't have an encoding or BOM problem.

Categories

Resources