Question Cannot Deserialize using XmlSerializer

njsokalski

Well-known member
Joined
Mar 16, 2011
Messages
102
Programming Experience
5-10
I have the following code that serializes an object:

Dim stream As New MemoryStream()
Dim xml As New XmlSerializer(GetType(SyncData))
xml.Serialize(stream, New SyncData(CType(Application.Current, App).Recipients, CType(Application.Current, App).Gifts))

However, when I later attempt to check whether it can be deserialized using the following code:

If New XmlSerializer(GetType(SyncData)).CanDeserialize(XmlReader.Create(stream)) Then

I receive the following error:

Data at the root level is invalid. Line 1, position 1.

The XML is all well formed, and the first line is the following:

<?xml version="1.0"?>

From what I could find, it sounds like this has something to do with encoding or some illegal character at the beginning of the file, but I am not sure how to fix it. Can anybody help me? Thanks.
 
You write to a MemoryStream and then try to read from it, normally stream position is then at end of content and reader won't find anything from there on. Try this before reading from it:
stream.Position = 0
 
Actually, I do include that. Here is the rest of the code for creating the XML, it serializes the object and then uploads it:

Private Sub btnUpload_Tap(sender As Object, e As System.Windows.Input.GestureEventArgs) Handles btnUpload.Tap
If Me.client IsNot Nothing Then
AddHandler Me.client.UploadCompleted, AddressOf Me.Client_UploadCompleted
Dim stream As New MemoryStream()
Dim xml As New XmlSerializer(GetType(SyncData))
xml.Serialize(stream, New SyncData(CType(Application.Current, App).Recipients, CType(Application.Current, App).Gifts))
stream.Position = 0
Me.client.UploadAsync("me/skydrive", datafilename, stream, OverwriteOption.Overwrite)
End If
End Sub

This uploads the file to my SkyDrive account, and then when I try to deserialize it I download it and use that stream, so the upload & download streams are different objects that don't even exist at the same time.
 
I don't know SkyDrive, but I can confirm what I replied in previous post and I can not replicate your CanDeserialize test failure, it must be something related specifically to the API you're using.
 
I don't know if this is the problem or not, but many of the things I managed to find online that mentioned this error said it had something to do with encoding. I do not specify a specific encoding anywhere in my code, so I am wondering if the fact that I use a MemoryStream while uploading is somehow causing an encoding problem. Here is my code again:

The upload code:

Dim stream As New MemoryStream()
Dim xml As New XmlSerializer(GetType(SyncData))
xml.Serialize(stream, New SyncData(CType(Application.Current, App).Recipients, CType(Application.Current, App).Gifts))
stream.Position = 0
Me.client.UploadAsync("me/skydrive", datafilename, stream, OverwriteOption.Overwrite)

The download code:

If New XmlSerializer(GetType(SyncData)).CanDeserialize(XmlReader.Create(e.Result)) Then
e.Result.Position = 0
Dim tempdata As SyncData = CType(New XmlSerializer(GetType(SyncData)).Deserialize(e.Result), SyncData)
CType(Application.Current, App).Recipients = tempdata.Recipients
CType(Application.Current, App).Gifts = tempdata.Gifts
End If
 
If New XmlSerializer(GetType(SyncData)).CanDeserialize(Xm lReader.Create(e.Result)) Then
e.Result.Position = 0
This is more than likely a bad idea, you can only read network related streams read once and they don't support seeking (feel free to check CanSeek property). Get rid of that check and attempt deserialization directly.
If you need to check out things for debugging, read the stream to local storage (file/memory) and continue operate on that and not e.Result.
 
I tried reducing the download code to just:

Dim tempdata As SyncData = CType(New XmlSerializer(GetType(SyncData)).Deserialize(e.Result), SyncData)

But it still gives the same error:

There is an error in XML document (1, 1).

So you may be correct about what you said (although CanSeek was True), but either way, the error is still the same even with just the one line, so there is still something I am missing. Any ideas? Thanks.
 
Save the data from stream to a file (FileStream) and have a look at it.
 
What should I do to save it to a FileStream? I couldn't seem to find a constructor or good method for creating a FileStream with the stream that I have. Thanks.
 
I changed the code to:

Private Sub Client_DownloadCompleted(sender As Object, e As LiveDownloadCompletedEventArgs)
If e.Error Is Nothing Then
System.Diagnostics.Debug.WriteLine("Checkpoint 1")
Dim fs As New FileStream("GiftTrackerData.xml", FileMode.Create)
e.Result.CopyTo(fs)
Dim tempdata As SyncData = CType(New XmlSerializer(GetType(SyncData)).Deserialize(fs), SyncData)
CType(Application.Current, App).Recipients = tempdata.Recipients
CType(Application.Current, App).Gifts = tempdata.Gifts
System.Diagnostics.Debug.WriteLine("Checkpoint 2")
Else
System.Diagnostics.Debug.WriteLine("Checkpoint 3")
MessageBox.Show(e.Error.Message, "Download Error", MessageBoxButton.OK)
System.Diagnostics.Debug.WriteLine("Checkpoint 4")
End If
RemoveHandler Me.client.DownloadCompleted, AddressOf Client_DownloadCompleted
End Sub

As you can see, I added System.Diagnostics.Debug.WriteLine statements at the beginning and end of both possibilities of the If statement. But what is probably the most confusing thing now is that when I run the code, it outputs "Checkpoint 1" (so the e.Error Is Nothing condition must be True), but then it gives the following error on the Checkpoint 3 line:

Attempt to access the method failed: System.IO.FileStream..ctor(System.String, System.IO.FileMode)

The thing that makes this so confusing is that Checkpoint 1 and Checkpoint 3 are in different parts of the If statement, how can it be executing code in the True AND False sections of the If statement? Also, how can I get it to show the whole error message instead of using the ..? I am guessing that the "ctor" in the error message is for constructor, so what did I do wrong in my FileStream constructor? Thanks.
 
Close the file: fs.Close()
You have already know you can't deserialize it, so use Notepad or something to have a look at the file contents.
 
On what line should I close the file? I have used Notepad to view the contents, they are exactly what I wanted and expected (well, that's what they look like in Notepad). It is all valid XML, no spaces at the beginning or end (at least none that I can see in Notepad), so the file contents seem correct. Thanks.
 
On what line should I close the file?
When you have copied the contents to it. Or do you expect to write more to the file after that? That would be weird.
 
Back
Top