Carlo
Carlo

Reputation: 25969

DataContractSerializer problem in Windows Phone 7

This happens only sometimes, but makes my files unreadable. The problem is that the DataContractSerializer adds a couple of >>> at the end of the XML files when serializing. Making them useless when trying to deserialize. Has anyone had this problem? Example:

<SomeObject xmlns="someNamespace">
</SomeObject>>>

Thanks.

Edit:

Actually no, that's not the problem. The file is fine this time, this is what it looks like:

<FavoriteClubManager xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/TicketingWP7.Preferences">
 <FavoriteClubs xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <d2p1:KeyValueOfstringboolean>
   <d2p1:Key>XXX</d2p1:Key>
   <d2p1:Value>true</d2p1:Value>
  </d2p1:KeyValueOfstringboolean>
 </FavoriteClubs>
</FavoriteClubManager>

And this is the error I get when trying to deserialize it:

"There was an error deserializing the object of type TicketingWP7.Preferences.FavoriteClubManager. Root element is missing."

But I don't see anything wrong with the file.

Code

Saving:

using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
{
    try
    {
        using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, FileMode.Create, file))
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(FavoriteClubManager));

            serializer.WriteObject(stream, this);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("There was an error saving your favorite clubs. " + ex.Message);
    }
}

Loading:

using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
{
    if (file.FileExists(_fileName))
    {
        try
        {
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, FileMode.Open, file))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(FavoriteClubManager));

                FavoriteClubManager temp = serializer.ReadObject(stream) as FavoriteClubManager;

                stream.Close();
            }

            _isLoaded = true;
        }
        catch (Exception ex)
        {
            MessageBox.Show("There was an error loading your favorite clubs. " + ex.Message);
        }
    }
}

Upvotes: 1

Views: 2194

Answers (2)

Carlo
Carlo

Reputation: 25969

Solved it. Pretty much cheated on it. I basically read the XML document with an XDocument, get the reader with XDocument.CreateReader() and pass the reader to the DataContractSerializer. That did the trick, I know it's not very elegant, but it's a solution. Hopefully I'll come up with a better solution in the future. For now, here's the code:

private bool Load()
{
    if (!_isLoaded)
    {
        using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (file.FileExists(_fileName))
            {
                string text = string.Empty;

                try
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, FileMode.Open, file))
                    {
                        if (stream.Length > 0)
                        {
                            XDocument document = GetXDocument(stream);

                            DataContractSerializer serializer = new DataContractSerializer(typeof(ClubManager));

                            ClubManager temp = serializer.ReadObject(document.CreateReader()) as ClubManager;

                            stream.Close();
                        }
                    }

                    _isLoaded = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("There was an error loading your favorite clubs. " + ex.Message);
                }
            }
        }
    }

    return _isLoaded;
}

private XDocument GetXDocument(IsolatedStorageFileStream stream)
{
    // read the file to find errors
    string documentText = ReadBytes(stream);

    return XDocument.Parse(documentText);
}

private static string ReadBytes(IsolatedStorageFileStream stream)
{
    byte[] buffer = new byte[stream.Length];

    stream.Read(buffer, 0, buffer.Length);

    string normal = string.Empty;
    string hex = BitConverter.ToString(buffer).Replace("-", "");

    while (hex.Length > 0)
    {
        // Use ToChar() to convert each ASCII value (two hex digits) to the actual character
        normal += System.Convert.ToChar(System.Convert.ToUInt32(hex.Substring(0, 2), 16)).ToString();
        // Remove from the hex object the converted value
        hex = hex.Substring(2, hex.Length - 2);
    }

    return normal;
}

Thanks!

Upvotes: 0

Matt Lacey
Matt Lacey

Reputation: 65566

Is the problem actually this:

  1. You serialize the object once and then save it to isolated storage.
  2. You read the object from isolated storage and deserialize it.
  3. You then update the object and reserialize it and then save it again.
  4. You read it back from isolated storage and can't deserialize it because of the extra characters.

If that's the flow to recreate the issue, I suspect that subsequent saved seializations are of a slightly smaller object and so create a serialized string which is smaller than that written previously.
When the later string is saved it is written on top of the previously saved string with the end of the old string being left there still.

The solution is to make sure that the existing file is deleted or it's contents removed before saving the new contents.

I had a similar issue previously and it was a pain to uncover.

BTW. You may also want to reconsider your serialization strategy with regard to performance. Take a look at this blog post by Kevin Marshall for more information.

Upvotes: 4

Related Questions