public byte[] SaveEnvelopeData(ImmutableEnvelope envelope)
        {
            //  string contract, Guid messageId, Uri sender,
            var itemContracts = new MessageContract[envelope.Items.Length];

            using (var content = new MemoryStream())
            {
                int position = 0;
                for (int i = 0; i < envelope.Items.Length; i++)
                {
                    var item = envelope.Items[i];

                    string name;
                    if (!_dataSerializer.TryGetContractNameByType(item.MappedType, out name))
                    {
                        var error = string.Format("Failed to find contract name for {0}", item.MappedType);
                        throw new InvalidOperationException(error);
                    }
                    // normal serializers have a nasty habbit of closing the stream after they are done
                    // we can suppress that or use a wrapper now instead
                    using (var itemStream = new MemoryStream())
                    {
                        _dataSerializer.Serialize(item.Content, itemStream);
                        var bytes = itemStream.ToArray();
                        content.Write(bytes, 0, bytes.Length);
                    }


                    int size            = (int)content.Position - position;
                    var attribContracts = EnvelopeConvert.ItemAttributesToContract(item.GetAllAttributes());
                    itemContracts[i] = new MessageContract(name, size, position, attribContracts);

                    position += size;
                }

                var envelopeAttribs = EnvelopeConvert.EnvelopeAttributesToContract(envelope.GetAllAttributes());


                var contract = new EnvelopeContract(envelope.EnvelopeId, envelopeAttribs, itemContracts,
                                                    envelope.DeliverOnUtc, envelope.CreatedOnUtc);

                using (var stream = new MemoryStream())
                {
                    // skip header
                    stream.Seek(EnvelopeHeaderContract.FixedSize, SeekOrigin.Begin);
                    // save envelope attributes
                    _envelopeSerializer.SerializeEnvelope(stream, contract);
                    var envelopeBytes = stream.Position - EnvelopeHeaderContract.FixedSize;
                    // copy data
                    content.WriteTo(stream);
                    // write the header
                    stream.Seek(0, SeekOrigin.Begin);
                    var header = new EnvelopeHeaderContract(EnvelopeHeaderContract.Schema2DataFormat, envelopeBytes, 0);
                    header.WriteToStream(stream);
                    return(stream.ToArray());
                }
            }
        }
        public ImmutableEnvelope ReadAsEnvelopeData(byte[] buffer)
        {
            var header = EnvelopeHeaderContract.ReadHeader(buffer);


            if (header.MessageFormatVersion != EnvelopeHeaderContract.Schema2DataFormat)
            {
                throw new InvalidOperationException("Unexpected message format");
            }


            EnvelopeContract envelope;

            using (var stream = new MemoryStream(buffer, EnvelopeHeaderContract.FixedSize, (int)header.EnvelopeBytes))
            {
                envelope = _envelopeSerializer.DeserializeEnvelope(stream);
            }

            var items = new ImmutableMessage[envelope.Messages.Length];

            for (var i = 0; i < items.Length; i++)
            {
                var  itemContract = envelope.Messages[i];
                var  attributes   = EnvelopeConvert.ItemAttributesFromContract(itemContract.Attributes);
                Type contractType;

                var itemPosition = EnvelopeHeaderContract.FixedSize + (int)header.EnvelopeBytes + (int)itemContract.ContentPosition;
                var itemSize     = (int)itemContract.ContentSize;
                if (_dataSerializer.TryGetContractTypeByName(itemContract.ContractName, out contractType))
                {
                    using (var stream = new MemoryStream(buffer, itemPosition, itemSize))
                    {
                        var instance = _dataSerializer.Deserialize(stream, contractType);

                        items[i] = new ImmutableMessage(contractType, instance, attributes, i);
                    }
                }
                else
                {
                    // we can't deserialize. Keep it as buffer
                    var bufferInstance = new byte[itemContract.ContentSize];
                    Buffer.BlockCopy(buffer, itemPosition, bufferInstance, 0, itemSize);
                    items[i] = new ImmutableMessage(null, bufferInstance, attributes, i);
                }
            }

            var envelopeAttributes = EnvelopeConvert.EnvelopeAttributesFromContract(envelope.EnvelopeAttributes);

            return(new ImmutableEnvelope(envelope.EnvelopeId, envelopeAttributes, items, envelope.DeliverOnUtc, envelope.CreatedOnUtc));
        }