Deserialization of corrupt XML hangs up XmlReader - c#

Accidently, I stumpled across a misformatted XML file having this content:
<?xml version="1.0" encoding="utf-8"?>
<MainModel xmlns:ctl="http://schemas.catelproject.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" ctl:graphid="1">
<DataId>123</DataId>
<DataName>Main Data Name</DataName>
<DataCollection ctl:graphid="2">
<SubModel ctl:graphid="3" xmlns:d0p0="http://schemas.datacontract.org/2004/07/CatelSpoiledDerialization.Models" i:type="d0p0:SubModel">
<SubId>200</
As the XML code shows, my example project (https://github.com/thoblerone/CatelSpoiledDerialization) is using the Catel framework, but deep debugging points towards a possible issue in System.Runtime.Serialization.XmlReader
The code to deserialize is pretty straght forward
var iXmlSer = SerializationFactory.GetXmlSerializer();
using var fileStream = File.Open(res.FileName, FileMode.Open);
var myData = iXmlSer.Deserialize<MainModel>(fileStream);
Yet, the call to Deserialize will never finish. Stepping through with the debugger, I see that the underlying .net XmlReader is calling MoveToContent while pointing to defective element (SubId) but the call will never succeed nor does it throw an exception, which I would gladly accept.
Am I missing come xml reader configuration that would check file conformity before tryinto to read the stuff?

Related

C# XmlTextWriter can't write to file

I have a problem with the XmlTextWriter class, I can't write to a file.
It is a console application I'm creating and the function looks like this.
private void WriteXML()
{
Console.WriteLine("Writing");
using (XmlTextWriter writer = new XmlTextWriter("DataW.xml", System.Text.Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteComment("This is a comment");
writer.WriteStartElement("WeeklyReview");
writer.WriteStartElement("DateTime");
writer.WriteStartAttribute("DateTime","09/04/2018 05:00");
writer.WriteElementString("Activity", "At Theodor");
writer.WriteElementString("Social", "Not Theodor,Theodor");
}
}
The result I'm getting is just a file with nothing in it. And in VS 2017 the file is shown with a white background and nothing in it.
The file I'm writing to is in the solution explorer and located in the same place as the file I'm reading from (which works).
I'm guessing the issue you're seeing is that the XML file created is blank or incomplete. If so, add a using statement around your code like so:
using (XmlTextWriter writer = new XmlTextWriter("DataW.xml", System.Text.Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteComment("This is a comment");
writer.WriteStartElement("Weekly Review"); //NB: A space in an element name!
writer.WriteStartElement("DateTime");
writer.WriteStartAttribute("09/04/2018 05:00"); //NB: a value given as an attribute name (consider: WriteAttributeString)!
writer.WriteElementString("Activity", "At Theodor");
writer.WriteElementString("Social", "Not Theodor,Theodor");
}
The reason for the issue is the methods you're calling write to an underlying stream rather than to the file system. To ensure that data is written to the file system you need to call the Flush method. Flush is called automatically when the writer is closed/disposed (but not when it's finalized). The using statement ensures that your writer is always disposed of correctly, so will ensure that your stream is flushed to disk.
For any other issues, you'd likely have an exception thrown (e.g. were there file access issues writing to the target location). If you're receiving an exception, please share that message and we can recommend a solution for that.
ps. The XML created by this is given below / it's not valid XML, so you'll have other issues down the line. I'll leave those for you to resolve, or for you to ask as another question should you have issues there. In the meantime, you can get some hints from the example in the documentation: https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmltextwriter.writestartattribute?view=netframework-4.7.2
<?xml version="1.0" encoding="utf-8"?>
<!--This is a comment-->
<Weekly Review>
<DateTime 09/04/2018 05:00="">
<Activity>At Theodor</Activity>
<Social>Not Theodor,Theodor</Social>
</DateTime>
</Weekly Review>
I know the Question is old, but in VB.net i got the same result.
I had to call XmlTextWriter.Flush() at the End to get Content in my File.

Generate XML File From Generated Object

I started with three (3) XSD files provided from an external party (one XSD links to the other two). I used the xsd.exe tool to generate a .NET object by running the following command: xsd.exe mof-simpleTypes.xsd mof-isp.xsd esf-submission.xsd /c and it generated a single CS file with a handful of partial objects.
I've created an XmlSerializerNamespaces object and fill with the namespaces required (two directly used in the provided sample XML file as well as two others that don't appear to be referenced). I have successfully generated an XML file using the following method:
private XmlDocument ConvertEsfToXml(ESFSubmissionType type)
{
var xml = new XmlDocument();
var serializer = new XmlSerializer(type.GetType());
string result;
using (var writer = new Utf8StringWriter()) //override of StringWriter to force UTF-8
{
serializer.Serialize(writer, type, _namespaces); //_namespaces object holds all 4 namespaces
result = writer.ToString();
}
xml.LoadXml(result);
return xml;
}
My problem that I'm facing is in the generated CS file, one of the objects has a property (another generated partial object) that is of type XmlElement. I have successfully built the object in code, and I'm having an issue converting the object to an XmlElement. The questions and answers I have found here on SO say convert it to an XmlDocument first and then take the DocumentElement property. This works, however the returned XML has namespaces embedded in the element as follows:
<esf:ESFSubmission xmlns:isp="http://www.for.gov.bc.ca/schema/isp" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:esf="http://www.for.gov.bc.ca/schema/esf">
<esf:submissionMetadata>
<esf:emailAddress>test#test.com</esf:emailAddress>
<esf:telephoneNumber>1234567890</esf:telephoneNumber>
</esf:submissionMetadata>
<esf:submissionContent>
<isp:ISPSubmission xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:esf="http://www.for.gov.bc.ca/schema/esf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:isp="http://www.for.gov.bc.ca/schema/isp">
<isp:ISPMillReport>
<isp:reportMonth>12</isp:reportMonth>
<isp:reportYear>2014</isp:reportYear>
<isp:reportComment>comment</isp:reportComment>
<isp:ISPLumberDetail>
<isp:species>FI</isp:species>
Note: this is just a partial of the generated XML file (for illustration purposes).
As you can see, each XML node is prefixed with the namespace variable. My question is: how can I do this in code? Is my approach sound and if so, then how do NOT include the namespaces in the ISPSubmission node OR if there is a better way to approach this problem that I overlooked, please provide insight. My desired outcome is to have all namespace definitions at the top of the document (their appropriate location) and not on the sub elements - as well as maintain the namespace variables on each element as illustrated above.
EDIT (after reggaeguitar's comment)
Here is the sample XML document I was provided
<?xml version="1.0" encoding="UTF-8"?>
<esf:ESFSubmission xmlns:esf="http://www.for.gov.bc.ca/schema/esf"
xmlns:isp="http://www.for.gov.bc.ca/schema/isp" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.for.gov.bc.ca/schema/esf esf-submission.xsd
http://www.for.gov.bc.ca/schema/isp mof-isp.xsd">
<esf:submissionMetadata>
<esf:emailAddress>mailto:eric.murphy#cgi.com</esf:emailAddress>
<esf:telephoneNumber>6044445555</esf:telephoneNumber>
</esf:submissionMetadata>
<esf:submissionContent>
<isp:ISPSubmission>
<isp:ISPMillReport>
<isp:reportMonth>06</isp:reportMonth>
<isp:reportYear>2014</isp:reportYear>
<isp:reportComment>Up to 4000 characters is permitted for notes in this element.</isp:reportComment>
<isp:ISPLumberDetail>
<isp:species>FI</isp:species>
<isp:lumberGrade>EC</isp:lumberGrade>
<isp:gradeDescription/>
<isp:size>2x4</isp:size>
<isp:finishType/>
<isp:length>10</isp:length>
<isp:thickWidthUom>IN</isp:thickWidthUom>
<isp:volumeUnitOfMeasure>MBM</isp:volumeUnitOfMeasure>
<isp:volume>11543.987</isp:volume>
<isp:amount>1467893.98</isp:amount>
<isp:invoiceNumber>837261</isp:invoiceNumber>
</isp:ISPLumberDetail>
<isp:ISPLumberDetail>
<isp:species>CE</isp:species>
<isp:lumberGrade/>
<isp:gradeDescription/>
<isp:size/>
<isp:finishType>D</isp:finishType>
<isp:thickness>40</isp:thickness>
<isp:width>100</isp:width>
<isp:thickWidthUom>MM</isp:thickWidthUom>
<isp:volumeUnitOfMeasure>MBM</isp:volumeUnitOfMeasure>
<isp:volume>9743.987</isp:volume>
<isp:amount>1247893.98</isp:amount>
<isp:invoiceNumber/>
</isp:ISPLumberDetail>
<isp:ISPChipDetail>
<isp:species>CE</isp:species>
<isp:unitOfMeasure>BDT</isp:unitOfMeasure>
<isp:wholeLogInd>N</isp:wholeLogInd>
<isp:destinationCode>FBCO</isp:destinationCode>
<isp:destinationDescription/>
<isp:volume>563</isp:volume>
<isp:amount>54463</isp:amount>
<isp:invoiceNumber>12345679</isp:invoiceNumber>
</isp:ISPChipDetail>
</isp:ISPMillReport>
<isp:ISPSubmitter>
<isp:millNumber>103</isp:millNumber>
<isp:contactName>Dave Marotto</isp:contactName>
<isp:contactEmail>eric.murphy#cgi.com</isp:contactEmail>
<isp:contactPhone>2507775555</isp:contactPhone>
<isp:contactPhoneExtension>1234</isp:contactPhoneExtension>
</isp:ISPSubmitter>
</isp:ISPSubmission>
</esf:submissionContent>
</esf:ESFSubmission>
Solved my problem by doing the whole thing in code and not even using the xsd.exe to generate a .NET object.

How do I add a new element to the existing XML file on Windows Phone 7 using LINQ to XML?

For the last couple of hours I was struggling with LINQ to XML on Windows Phone 7. I simply just want to add new element to an existing XML file.
XElement newItem = new XElement("item",new XAttribute("id",3),
new XElement("content","Buy groceries"),
new XElement("status","false"));
IsolatedStorageFile isFile = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream stream = new IsolatedStorageFileStream("/Items.xml", System.IO.FileMode.Open, isFile);
XDocument loadedDoc = XDocument.Load(stream);
loadedDoc.Add(newItem);
loadedDoc.Save(stream);
Generally I'm experiencing very weird behavior. Sometimes I am getting an error "Operation not permitted on IsolatedStorageFileStream.". Sometimes it is "Root element is missing" and sometimes it is "Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it." If, for example, I would change System.IO.FileMode.Open to Create I would get "Root element is missing" but apart from that there doesn't seem to be any pattern according to which error occurs.
It all seems like its my XML file which causes the problem:
<?xml version="1.0" encoding="utf-8" ?>
<items>
<item id="1">
<content>Get groceries</content>
<status>false</status>
</item>
<item id="2">
<content>Wash your car</content>
<status>true</status>
</item>
</items>
It doesn't get any simpler than that and I am absolutely sure I don't have any white spaces before the declaration in the actual XML file.
And to make it all even more weird I have downloaded little sample application that uses the same technique of writing to XML file. When I try to run it I am getting a very familiar error:
Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it.
Here is link to that thread: http://mobileworld.appamundi.com/blogs/petevickers/archive/2010/12/06/windows-phone-7-linq-to-xml-corruption.aspx/
Yesterday I installed Windows Phone SDK 7.1 BETA. Could that be causing the problem?
It seems like the problem is with locating xml file in isolated storage. I have created completely new project and new xml file inside.
Thats the only code I have:
// Constructor
public MainPage()
{
InitializeComponent();
var isFile = IsolatedStorageFile.GetUserStoreForApplication();
var stream = isFile.OpenFile("file.xml", System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
}
I'am still getting: Operation not permitted on IsolatedStorageFileStream. I have tried going into properties of file.xml changing Built action and copy to output directory but that didn't work. I tried adding:
isFile.Dispose();
I also tried adding conditional statement:
if (isFile.FileExists("file.xml"))...
But he couldn't find the file.
I have never been so stuck in my life. Please advice me what else can i try.
You're trying to save to the same stream you loaded from - but without "rewinding" it to the start. I don't know whether isolated storage streams are seekable, but you can try just changing the code to:
XDocument loadedDoc = XDocument.Load(stream);
loadedDoc.Add(newItem);
stream.Position = 0;
loadedDoc.Save(stream);
Note that while we don't need to reset the size of stream in this case as we're adding content, in other cases you might need to do so in order to avoid "leftover" bits at the end of the file.
Alternatively, load the document and close the stream, then open up a new stream to the same file. Note that you should use using statements to close the streams after each use, e.g.
using (var isFile = IsolatedStorageFile.GetUserStoreForApplication())
{
XDocument loadedDoc;
using (var stream = isFile.OpenFile("/Items.xml", FileMode.Open))
{
loadedDoc = XDocument.Load(stream);
}
loadedDoc.Add(newItem);
using (var stream = isFile.OpenFile("/Items.xml", FileMode.Create))
{
loadedDoc.Save(stream);
}
}

Saving sql server xml result to disk

I have a C# application that calls a stored procedure that produces an xml result (using FOR XML Explicit) that I want to save to disk. Doing some research I have found the following method:
var data = new DataSet();
XmlReader reader = cmd.ExecuteXmlReader();
data.ReadXmlSchema(reader);
data.ReadXml(reader, XmlReadMode.Fragment);
data.WriteXml(filename);
However this outputs the following in the file:
<?xml version="1.0" standalone="yes" ?>
<NewDataSet />
I think this method might only work for XML Raw and XML Auto however I can look through the dataset's tables and see the data is there.
UPDATE: I was able to get it to work by not reading the XmlSchema and by not specifying the XmlReadMode.
I was able to get it to work by not reading the XmlSchema and by not specifying the XmlReadMode.

Exception when trying to deserialize a xml file

Im trying to deserialize an XML file with XmlSerializer, however im getting this exception:
"There is an error in XML document (1,
2)" The innerexception is:
"<Mymessage
xmlns='http://MyMessages/'> was not
expected."
Which is the very first line in the XML file. my guess is that it has something to do with the xmlns.
I tried to ask Google, and then tried to add the following line to my code
[XmlRoot("MyMessage", Namespace="'http://MyMessages/")]
But I still get the same exception.
In the constructor of the XmlSerializer i needed to specify a default namespace, after doing that everything worked just fine
Please provide the full XML file code to help understand the issue better.
Also put this as the first line in the xml file and see if this solves the issue
<?xml version="1.0" encoding="utf-8"?>
Further to CruelIO's response, I resolved the error by adding:
[XmlRoot("RenderResult", Namespace = "http://mynamespace.uri.org")]
to the class that I was trying to deserialize. e.g: the serialization code was:
RenderResult result;
using (var memoryStream = new MemoryStream(data))
{
var xmlSerializer = new XmlSerializer(typeof(RenderResult));
result = (RenderResult)xmlSerializer.Deserialize(memoryStream);
}
and my class looked like this:
[XmlRoot("RenderResult", Namespace = "http://mynamespace.uri.org")]
public class RenderResult
{
}
It sounds like you have a borked xml file. Easy ways to find out:
try loading it into an xml viewer
or just make sure it has a .xml extension and load in VS or IE
or run xsd.exe over it
If they complain, then the xml is certainly corrupt.
If they work fine, and display your data, then you probably have the serialization attributes wrong. Try using xsd.exe with the "/classes" switch to see what it would do with it...

Categories