0

Sorry for super long question i did not want to leave out any code.

This is the code to encrypt and serialize...

public class EncryptionSerialiser
{
    byte[] key = {1, 2, 3, 4, 5, 6, 7, 8}; // Where to store these keys is the tricky part, 
    // you may need to obfuscate them or get the user to input a password each time
    byte[] iv = {1, 2, 3, 4, 5, 6, 7, 8};
    //string path = Application.StartupPath + @"\" + "test.ser";
    DESCryptoServiceProvider des = new DESCryptoServiceProvider();

    public void EncryptThenSerialise(object obj, string pathandfilename)
    {
        // Encryption
        using (var fs = new FileStream(pathandfilename, FileMode.Create, FileAccess.Write))
        using (var cryptoStream = new CryptoStream(fs, des.CreateEncryptor(key, iv), CryptoStreamMode.Write))
        {
            BinaryFormatter formatter = new BinaryFormatter();

            // This is where you serialize the class
            try
            {
                formatter.Serialize(cryptoStream, obj);
            }
            catch (Exception ex)
            {
                // MessageBox.Show(ex.ToString());
            }
            //  cryptoStream.Close();
        }
    }

    public T DecryptThenDeSerialise<T>(object obj, string pathandfilename)
    {
        // Decryption
        using (var fs = new FileStream(pathandfilename, FileMode.Open, FileAccess.Read))
        using (var cryptoStream = new CryptoStream(fs, des.CreateDecryptor(key, iv), CryptoStreamMode.Read))
        {
            BinaryFormatter formatter = new BinaryFormatter();

            // This is where you deserialize the class
            T deserialized = (T) formatter.Deserialize(cryptoStream);

            return deserialized;
        }
    }

My High Level Dictionary class...

[Serializable]
public class HighLevelDictionary : SerializableDictionary<string, LowLevelDictionary>
{
    protected HighLevelDictionary(SerializationInfo info, StreamingContext context)
    {
        int itemCount = info.GetInt32("ItemCount");
        for (int i = 0; i < itemCount; i++)
        {
            KeyValuePair<string,  LowLevelDictionary> kvp =
                (KeyValuePair<string, LowLevelDictionary>)
                info.GetValue(String.Format("Item{0}", i),
                    typeof(KeyValuePair<string,  LowLevelDictionary

            this.Add(kvp.Key, kvp.Value);
        }
    }

    public HighLevelDictionary()
    {          
    }
}

My LowlevelDictionary class...

[Serializable]
public class LowLevelDictionary : SerializableDictionary<string, decimal>
{
    protected LowLevelDictionary(SerializationInfo info, StreamingContext context)
    {
        int itemCount = info.GetInt32("ItemCount");
        for (int i = 0; i < itemCount; i++)
        {
            KeyValuePair<string, decimal> kvp =
                (KeyValuePair<string, decimal>)
                info.GetValue(String.Format("Item{0}", i),
                    typeof(KeyValuePair<string, decimal>));

            this.Add(kvp.Key, kvp.Value);
        }
    }

    public LowLevelDictionary()
    {
    }
}

My serializable SerializableDictionary Class...

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

[Serializable()]
public class SerializableDictionary<TKey, TVal> : Dictionary<TKey, TVal>, IXmlSerializable, ISerializable
{
    #region Constants
    private const string DictionaryNodeName = "Dictionary";
    private const string ItemNodeName = "Item";
    private const string KeyNodeName = "Key";
    private const string ValueNodeName = "Value";
    #endregion
    #region Constructors
    public SerializableDictionary()
    {
    }

    public SerializableDictionary(IDictionary<TKey, TVal> dictionary)
        : base(dictionary)
    {
    }

    public SerializableDictionary(IEqualityComparer<TKey> comparer)
        : base(comparer)
    {
    }

    public SerializableDictionary(int capacity)
        : base(capacity)
    {
    }

    public SerializableDictionary(IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer)
        : base(dictionary, comparer)
    {
    }

    public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
        : base(capacity, comparer)
    {
    }

    #endregion
    #region ISerializable Members

    protected SerializableDictionary(SerializationInfo info, StreamingContext context)
    {
        int itemCount = info.GetInt32("ItemCount");
        for (int i = 0; i < itemCount; i++)
        {
            KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format("Item{0}", i), typeof(KeyValuePair<TKey, TVal>));
            this.Add(kvp.Key, kvp.Value);
        }
    }

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("ItemCount", this.Count);
        int itemIdx = 0;
        foreach (KeyValuePair<TKey, TVal> kvp in this)
        {
            info.AddValue(String.Format("Item{0}", itemIdx), kvp, typeof(KeyValuePair<TKey, TVal>));
            itemIdx++;
        }
    }

    #endregion
    #region IXmlSerializable Members

    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
    {
        //writer.WriteStartElement(DictionaryNodeName);
        foreach (KeyValuePair<TKey, TVal> kvp in this)
        {
            writer.WriteStartElement(ItemNodeName);
            writer.WriteStartElement(KeyNodeName);
            KeySerializer.Serialize(writer, kvp.Key);
            writer.WriteEndElement();
            writer.WriteStartElement(ValueNodeName);
            ValueSerializer.Serialize(writer, kvp.Value);
            writer.WriteEndElement();
            writer.WriteEndElement();
        }
        //writer.WriteEndElement();
    }

    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
    {
        if (reader.IsEmptyElement)
        {
            return;
        }

        // Move past container
        if (!reader.Read())
        {
            throw new XmlException("Error in Deserialization of Dictionary");
        }

        //reader.ReadStartElement(DictionaryNodeName);
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            reader.ReadStartElement(ItemNodeName);
            reader.ReadStartElement(KeyNodeName);
            TKey key = (TKey)KeySerializer.Deserialize(reader);
            reader.ReadEndElement();
            reader.ReadStartElement(ValueNodeName);
            TVal value = (TVal)ValueSerializer.Deserialize(reader);
            reader.ReadEndElement();
            reader.ReadEndElement();
            this.Add(key, value);
            reader.MoveToContent();
        }
        //reader.ReadEndElement();

        reader.ReadEndElement(); // Read End Element to close Read of containing node
    }

    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    #endregion
    #region Private Properties
    protected XmlSerializer ValueSerializer
    {
        get
        {
            if (valueSerializer == null)
            {
                valueSerializer = new XmlSerializer(typeof(TVal));
            }
            return valueSerializer;
        }
    }

    private XmlSerializer KeySerializer
    {
        get
        {
            if (keySerializer == null)
            {
                keySerializer = new XmlSerializer(typeof(TKey));
            }
            return keySerializer;
        }
    }
    #endregion
    #region Private Members
    private XmlSerializer keySerializer = null;
    private XmlSerializer valueSerializer = null;
    #endregion
}

My Test Code...

EncryptionSerialiser encryptionSerialiser = new EncryptionSerialiser();

GlobalApplicationSettings globalApplicationSettings = new GlobalApplicationSettings();
// CurrentSingleValueOperation.Save();

HighLevelDictionary highLevelDictionary = new HighLevelDictionary();

LowLevelDictionary lowLevelDictionary = new LowLevelDictionary();
lowLevelDictionary.Add("S1", 0.00m);
lowLevelDictionary.Add("S2", 0.00m);

LowLevelDictionary lowLevelDictionary2 = new LowLevelDictionary();
lowLevelDictionary2.Add("S1", 4.00m);
lowLevelDictionary2.Add("S2", 4.00m);

highLevelDictionary.Add("One", lowLevelDictionary);
highLevelDictionary.Add("tWO", lowLevelDictionary2);

encryptionSerialiser.EncryptThenSerialise(highLevelDictionary,
    globalApplicationSettings.PriceSetsFullPath + "SVO0.crypt");

HighLevelDictionary extraHighLevelDictionary = new HighLevelDictionary();

extraHighLevelDictionary = encryptionSerialiser.DecryptThenDeSerialise<HighLevelDictionary>(extraHighLevelDictionary,
    globalApplicationSettings.PriceSetsFullPath + "SVO0.crypt");

Issue

As you can see from the above image the lowered level dictionary stuff seems lost after deserialization (indicated by the null value, although before serialisation i checked and it seems fine.

Any ideas anyone?

slawekwin
  • 6,270
  • 1
  • 44
  • 57
user3755946
  • 804
  • 1
  • 10
  • 22
  • [SerializableDictionary<>](http://stackoverflow.com/a/3672070/1997232). – Sinatr Aug 23 '16 at 10:28
  • 2
    The constructor for HighLevelDictionary is private. Try making public. – jdweng Aug 23 '16 at 10:31
  • Thanks for your suggestion it's not private it's protected, i tried making it private anyway still did not work. – user3755946 Aug 23 '16 at 10:41
  • try disabling encryption and see if it's serialized properly – slawekwin Aug 23 '16 at 11:04
  • @slawekwin disabled the encryption and it still fails. – user3755946 Aug 23 '16 at 12:04
  • But is the serialized output what you expected? Meaning, is the `LowLevelDictionary` serialized properly? – slawekwin Aug 23 '16 at 12:07
  • @slawekwin yes looks like it is, although it' is serialised to binary so it is not the easiest read. I have changed some of the decimals in the lower level dictionary though and they appear to have changed correctly. – – user3755946 Aug 23 '16 at 12:25
  • You could temporarily use xml or json serializer for debugging purposes. Anyway, in this case try stepping through your deserialization method in the debugger. There is nothing obviously wrong with your code I can see without it and it is quite easy to get wrong. – slawekwin Aug 23 '16 at 12:32
  • @slawekwin I just successfully serialized and deserilised the LowLevel Dictionary on it's own so it musb be something to do with the fact one dictionary contains another. not sure what though. – user3755946 Aug 23 '16 at 12:38
  • @slawekwin it deserializes fine from xml. can't work this out – user3755946 Aug 23 '16 at 15:53

2 Answers2

1

Your last comment on the question states that your implementation works fine for xml serialization, but not for the BinaryFormatter you use in EncryptionSerialiser class. This is the crucial piece of information here.

Please note that your serialization implementation in SerializableDictionary base class is based on implementing IXmlSerializable interface. This interface is called by XmlSerializer, but is not used by binary serialization. I guess that the higher level Dictionary is by default serialized because of the Serializable attribute.

You will have to implement suitable interface for binary approach. I would start with this

slawekwin
  • 6,270
  • 1
  • 44
  • 57
1

You are using BinaryFormatter to serialize your dictionary, not XmlSerializer, and have implemented custom streaming constructors and GetObjectData() methods for this purpose - which apparently are not working. However, your base class Dictionary<TKey, TValue> already implements ISerializable, thus it already has its own streaming constructor and GetObjectData() method. Rather than attempting to create your own versions of these methods, you can just use them and they will work:

[Serializable]
public class HighLevelDictionary : SerializableDictionary<string, LowLevelDictionary>
{
    public HighLevelDictionary()
    {
    }

    protected HighLevelDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
}

[Serializable]
public class LowLevelDictionary : SerializableDictionary<string, decimal>
{
    protected LowLevelDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }

    public LowLevelDictionary()
    {
    }
}

[Serializable()]
public class SerializableDictionary<TKey, TVal> : Dictionary<TKey, TVal>, IXmlSerializable
{
    #region Constructors
    public SerializableDictionary()
    {
    }

    public SerializableDictionary(IDictionary<TKey, TVal> dictionary)
        : base(dictionary)
    {
    }

    public SerializableDictionary(IEqualityComparer<TKey> comparer)
        : base(comparer)
    {
    }

    public SerializableDictionary(int capacity)
        : base(capacity)
    {
    }

    public SerializableDictionary(IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer)
        : base(dictionary, comparer)
    {
    }

    public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
        : base(capacity, comparer)
    {
    }

    #endregion

    #region ISerializable members

    protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }

    #endregion

    #region Constants
    private const string DictionaryNodeName = "Dictionary";
    private const string ItemNodeName = "Item";
    private const string KeyNodeName = "Key";
    private const string ValueNodeName = "Value";
    #endregion

    #region IXmlSerializable Members

    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
    {
        //writer.WriteStartElement(DictionaryNodeName);
        foreach (KeyValuePair<TKey, TVal> kvp in this)
        {
            writer.WriteStartElement(ItemNodeName);
            writer.WriteStartElement(KeyNodeName);
            KeySerializer.Serialize(writer, kvp.Key);
            writer.WriteEndElement();
            writer.WriteStartElement(ValueNodeName);
            ValueSerializer.Serialize(writer, kvp.Value);
            writer.WriteEndElement();
            writer.WriteEndElement();
        }
        //writer.WriteEndElement();
    }

    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
    {
        if (reader.IsEmptyElement)
        {
            return;
        }

        // Move past container
        if (!reader.Read())
        {
            throw new XmlException("Error in Deserialization of Dictionary");
        }

        //reader.ReadStartElement(DictionaryNodeName);
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            reader.ReadStartElement(ItemNodeName);
            reader.ReadStartElement(KeyNodeName);
            TKey key = (TKey)KeySerializer.Deserialize(reader);
            reader.ReadEndElement();
            reader.ReadStartElement(ValueNodeName);
            TVal value = (TVal)ValueSerializer.Deserialize(reader);
            reader.ReadEndElement();
            reader.ReadEndElement();
            this.Add(key, value);
            reader.MoveToContent();
        }
        //reader.ReadEndElement();

        reader.ReadEndElement(); // Read End Element to close Read of containing node
    }

    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    #endregion
    #region Private Properties
    protected XmlSerializer ValueSerializer
    {
        get
        {
            if (valueSerializer == null)
            {
                valueSerializer = new XmlSerializer(typeof(TVal));
            }
            return valueSerializer;
        }
    }

    private XmlSerializer KeySerializer
    {
        get
        {
            if (keySerializer == null)
            {
                keySerializer = new XmlSerializer(typeof(TKey));
            }
            return keySerializer;
        }
    }
    #endregion
    #region Private Members
    private XmlSerializer keySerializer = null;
    private XmlSerializer valueSerializer = null;
    #endregion
}

Sample fiddle.

That being said, BinaryFormatter is not a great choice for persisting data. See for instance What are the deficiencies of the built-in BinaryFormatter based .Net serialization? and Assembly Independent Serialization in .NET. XmlSerializer is one obvious alternative since you have already implemented IXmlSerializable. If you require a binary format you could consider .

dbc
  • 104,963
  • 20
  • 228
  • 340