PaulR
PaulR

Reputation: 891

Serialise & deserialize CRM EntityCollection

I seem to recall in CRM 4, you could retrieve an EntityCollection to and from a file on disk. I would like to do this as part of writing both a backup mechanism, and a data transfer for a CRM Online instance.

However this does not seem to work correctly in CRM 2011 as the Attributes collection of each Entity contains a list of empty KeyValuePairOfStringObjects and the FormattedValues collection of each entity contains a list if empty KeyValuePairOfStringStrings.

Therefore the names and values of the entity's attributes have not been included in the serialization, however they definitely have values when viewed in the VS debugger.

Is there a way I can programatically store these collections to file so that they may be later deserialized and used to restore data to where they came from or to a parallel target instance eg for testing offline?

Upvotes: 1

Views: 3076

Answers (2)

crisfervil
crisfervil

Reputation: 131

Here is my version of the serialization method proposed by @bigtv

private string Serialize(EntityCollection records)
{
    string retVal = null;   
    using(var tw = new StringWriter())
    using (var xw = new XmlTextWriter(tw))
    {
        var ser = new DataContractSerializer(typeof(EntityCollection));
        ser.WriteObject(xw, records);
        retVal = tw.ToString();
    }
    return retVal;
}

Upvotes: 2

bigtv
bigtv

Reputation: 2711

I had the exact same requirement to save the raw EntityCollection response back from a CRM FetchRequest. I got the same result as you from standard XmlSerializer, the trick is to use the same serializer that CRM is using under the hood.

Take a look at the DataContractSerializer class: MSDN reference is here

This is the helper class I then ended up writing:

    class Serialiser
    {
        /// <summary>
        /// The xml serialiser instance.
        /// </summary>
        private readonly DataContractSerializer dataContractSerialiser;

        /// <summary>
        /// Initializes a new instance of the <see cref="SerialiserService.Serialiser"/> class.
        /// </summary>
        /// <param name="typeToSerilaise">The type to serilaise.</param>
        public Serialiser(Type typeToSerilaise)
        {
            this.dataContractSerialiser = new DataContractSerializer(typeToSerilaise);
        }

        /// <summary>
        /// Serialises the specified candidate.
        /// </summary>
        /// <param name="candidate">The candidate.</param>
        /// <returns>A serialised representaiton of the specified candidate.</returns>
        public byte[] Serialise(object candidate)
        {
            byte[] output;

            using (var ms = new MemoryStream())
            {

                this.dataContractSerialiser.WriteObject(ms, candidate);
                var numberOfBytes = ms.Length;

                output = new byte[numberOfBytes];

                // Note: Only copy the exact stream length to avoid capturing trailing null bytes.
                Array.Copy(ms.GetBuffer(), output, numberOfBytes);
            }

            return output;
        }

        /// <summary>
        /// Deserialises the specified serialised instance.
        /// </summary>
        /// <param name="serialisedInstance">The serialised instance.</param>
        /// <returns>A deserialised instance of the specified type.</returns>
        public object Deserialise(byte[] serialisedInstance)
        {
            object output;

            using (var ms = new MemoryStream(serialisedInstance))
            using (var reader = XmlDictionaryReader.CreateTextReader(ms, new XmlDictionaryReaderQuotas()))
            {
                output = this.dataContractSerialiser.ReadObject(reader);
            }

            return output;
        }
    }

Usage:

new Serialiser(typeof(EntityCollection));

You can then read or write the byte[] to disk.

Upvotes: 0

Related Questions