1

Given the following class design:

 public class AllUserCollections
    {
        public List<UserCollection> UserCollections { get; set; }

        public AllUserCollections()
        {
            this.UserCollections = new List<UserCollection> ();
        }
    }

    public class UserCollection
    {
        public string UserGroup { get; set; }
        public Dictionary<int,User> Users { get; set; }

        public UserCollection(string userGroup)
        {
            this.UserGroup = userGroup;
            this.Users = new Dictionary<int, User> ();
        }
    }

    public class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Location { get; set; }
        public AgeGroup UserAgeGroup { get; set; }
    }

    public enum AgeGroup
    {
        Twenties,
        Thirties,
        Fourties,
    }

How can I serialize this to XML using my existing serialization class?

public static class HardDriveService
    {
        private static string docsFolderPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
        private const string fileName = "AllUserCollections.xml";
        private static string filePath = Path.Combine(docsFolderPath, fileName);

        private static bool FileExists(string fullFilePath)
        {
            if (File.Exists (fullFilePath)) 
                return true;

            return false;
        }

        public static void Save(AllUserCollections allUserCollections)
        {
            if (FileExists(filePath))
            {
                File.Delete (filePath);
            }

            XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());
            using(StreamWriter writer = new StreamWriter(filePath))
            {
                serializer.Serialize(writer.BaseStream, allUserCollections);
            }
        }

        public static AllUserCollections Read()
        {
            AllUserCollections allUserCollections = new AllUserCollections();
            XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());

            if (FileExists(filePath))
            {
                StreamReader reader = new StreamReader(filePath);
                object deserialized = serializer.Deserialize(reader.BaseStream);
                allUserCollections = (AllUserCollections)deserialized;
            }

            return allUserCollections;
        }


    }//End of class.

ISSUES

My code seems to fail on this line -

XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());

I wonder if it's to do with the class needing to be explicitly marked as "serializable"? How would I do this?

Usage This code will run on an iphone and save/read directly from an app to XML on the iPhone hard drive.

Charles
  • 50,943
  • 13
  • 104
  • 142
Goober
  • 13,146
  • 50
  • 126
  • 195

4 Answers4

3

XMLSerializer doesn't support Dictionary out of the box. Your UserCollection class has a Dictionary. See this link for a workaround. Why doesn't XmlSerializer support Dictionary?

Other than that the XMLSerializer requires that your classes have default constructors (UserCollection and User don't) and each of them must have the [Serializable] attribute.

Community
  • 1
  • 1
StevieB
  • 982
  • 7
  • 15
1

You could use XElement to build up an XML format. You could use them along the following lines:

public static XElement ToXml(this User user)
{
    if (user == null)
    {
        throw new ArgumentException("User can not be null.");
    }

    XElement userElement = new XElement("User");
    userElement.Add(new XElement("ID", user.ID));
    userElement.Add(new XElement("Name", user.Name));
    userElement.Add(new XElement("Location", user.Location));
    userElement.Add(new XElement("UserAgeGroup", user.UserAgeGroup));

    return userElement;
}

public static string ToXml(this UserCollection userCollection)
{
    if (userCollection == null)
    {
        throw new ArgumentException("UserCollection can not be null.");
    }

    XElement userCollectionElement = new XElement("UserCollection");
    userCollectionElement.Add(new XElement("UserGroup", userCollection.UserGroup));
    userCollectionElement.Add(new XElement("Users", 
                                           userCollection.Users.Select(x => new XElement("User", x.ToXml()));

    return userCollectionElement;
}

Calling .ToString() on an XElement should give you an xml-formatted string.

Sam
  • 1,358
  • 15
  • 24
0

Here you have 2 choices XmlSerializer(which will not work with Dictionary or List type deserialization ) or you can use DataContractSerializer which added in .net 3.0 and has a lot advantages here are few: form this post

  • optimized for speed (about 10% faster than XmlSerializer, typically)

  • in "opt-in" - only stuff you specifically mark as [DataMember] will be serialized

  • doesn't support XML attributes (for speed reasons)

Note : you should add reference to the C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Runtime.Serialization.dll

//to serialize 
        SerializeHelper.Serialize("your filename" ,new AllUserCollections());
// deserialize
        var usertCollections = SerializeHelper.Deserialize<AllUserCollections>("yourfile name"); 


//code 
 [DataContract]
    public class AllUserCollections
    {
        public List<UserCollection> UserCollections { get; set; }

        public AllUserCollections()
        {
            this.UserCollections = new List<UserCollection>();
        }
    }
    [DataContract()]
    public class UserCollection
    {
         [DataMember]
        public string UserGroup { get; set; }

         [DataMember]
        public Dictionary<int, User> Users { get; set; }

        public UserCollection(string userGroup)
        {
            this.UserGroup = userGroup;
            this.Users = new Dictionary<int, User>();
        }
    }
    [DataContract()]
    public class User
    {   [DataMember]
        public int ID { get; set; }
         [DataMember]
        public string Name { get; set; }
         [DataMember]
        public string Location { get; set; }
         [DataMember]
        public AgeGroup UserAgeGroup { get; set; }
    }
     [DataContract]
    public enum AgeGroup
    {
        Twenties,
        Thirties,
        Fourties,
    }
    public  static class  SerializeHelper
    {
         public static void Serialize<T>(string fileName, T obj)
    {
        using (FileStream writer = new FileStream(fileName, FileMode.Create))
        {
         DataContractSerializer ser =
            new DataContractSerializer(typeof(T));
        ser.WriteObject(writer, obj);
        writer.Close();   
        }


    }

    public static T Deserialize<T>(string fileName)
    {
        T des;
        using (FileStream fs = new FileStream(fileName,FileMode.Open))
        {
        XmlDictionaryReader reader =
            XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
        DataContractSerializer ser = new DataContractSerializer(typeof(T));
        des =
            (T)ser.ReadObject(reader, true);
        reader.Close();
        fs.Close(); 

        }

        return des;
    }
    }
Community
  • 1
  • 1
BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47
0

FULL WORKING SOLUTION

Data Model

using System;
using System.Collections.Generic;

namespace iPhoneHardDriveCRUDPrototype
{
    [Serializable]
    public class AllUserCollections
    {
        public List<UserCollection> UserCollections { get; set; }

        public AllUserCollections()
        {
            this.UserCollections = new List<UserCollection> ();
        }
    }

    [Serializable]
    public class UserCollection
    {
        public string UserGroup { get; set; }
        public SerializableDictionary<int,User> Users { get; set; }

        public UserCollection()
        {
            this.Users = new SerializableDictionary<int, User> ();
        }

        public UserCollection(string userGroup)
        {
            this.UserGroup = userGroup;
            this.Users = new SerializableDictionary<int, User> ();
        }
    }

    [Serializable]
    public class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Location { get; set; }
        public AgeGroup UserAgeGroup { get; set; }

        public User()
        {

        }
    }

    [Serializable]
    public enum AgeGroup
    {
        Twenties,
        Thirties,
        Fourties,
    }
}

Serializable Dictionary

using System;
using System.Xml.Serialization;
using System.Collections.Generic;

namespace iPhoneHardDriveCRUDPrototype
{
    [XmlRoot("dictionary")] 
    public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable 
    { 
        public System.Xml.Schema.XmlSchema GetSchema() 
        { 
            return null; 
        }

        public void ReadXml(System.Xml.XmlReader reader) 
        { 
            XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); 
            XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

            bool wasEmpty = reader.IsEmptyElement; 
            reader.Read();

            if (wasEmpty) 
                return;

            while (reader.NodeType != System.Xml.XmlNodeType.EndElement) 
            { 
                reader.ReadStartElement("item"); 
                reader.ReadStartElement("key"); 
                TKey key = (TKey)keySerializer.Deserialize(reader); 
                reader.ReadEndElement(); 
                reader.ReadStartElement("value"); 
                TValue value = (TValue)valueSerializer.Deserialize(reader); 
                reader.ReadEndElement(); 
                this.Add(key, value); 
                reader.ReadEndElement(); 
                reader.MoveToContent(); 
            } 
            reader.ReadEndElement(); 
        }

        public void WriteXml(System.Xml.XmlWriter writer) 
        { 
            XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); 
            XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

            foreach (TKey key in this.Keys) 
            { 
                writer.WriteStartElement("item"); 
                writer.WriteStartElement("key"); 
                keySerializer.Serialize(writer, key); 
                writer.WriteEndElement(); 
                writer.WriteStartElement("value"); 
                TValue value = this[key]; 
                valueSerializer.Serialize(writer, value); 
                writer.WriteEndElement(); 
                writer.WriteEndElement(); 
            } 
        }



    }//End of Class....
}

Serializer

using System;
using System.IO;
using System.Xml.Serialization;
using System.Reflection;
using System.Collections.Generic;

namespace iPhoneHardDriveCRUDPrototype
{
    public static class HardDriveService
    {
        private static string docsFolderPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
        private const string fileName = "AllUserCollections.xml";
        private static string filePath = Path.Combine(docsFolderPath, fileName);

        private static bool FileExists(string fullFilePath)
        {
            if (File.Exists (fullFilePath)) 
                return true;

            return false;
        }

        public static void Save(AllUserCollections allUserCollections)
        {
            if (FileExists(filePath))
            {
                File.Delete (filePath);
            }

            XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());
            using(StreamWriter writer = new StreamWriter(filePath))
            {
                serializer.Serialize(writer.BaseStream, allUserCollections);
            }
        }

        public static AllUserCollections Read()
        {
            AllUserCollections allUserCollections = new AllUserCollections();
            XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());

            if (FileExists(filePath))
            {
                StreamReader reader = new StreamReader(filePath);
                object deserialized = serializer.Deserialize(reader.BaseStream);
                allUserCollections = (AllUserCollections)deserialized;
            }

            return allUserCollections;
        }


    }//End of class.
}
Goober
  • 13,146
  • 50
  • 126
  • 195
  • no it's not a full working solution as you cannot deserialize the dictionary and the List types my solution which use datacontractserializer will work better – BRAHIM Kamel Dec 19 '13 at 12:53
  • DataContractSerializer isn't supported by MonoTouch. And yes, the serializable dictionary class I posted does work. – Goober Dec 19 '13 at 13:00
  • first you have not added moonotouch tag second DataContractSerializer is supported in Monotouch – BRAHIM Kamel Dec 19 '13 at 13:17