public override void TransferData(BackupDataSource destination, ProgressChange progressChange)
        {
            // Get the backup file from blob
            CloudBlockBlob zipBlob   = this.container.GetBlockBlobReference(this.filename);
            BlobStream     zipStream = zipBlob.OpenRead();

            // Create a temp file for xml file
            CloudBlockBlob xmlBlob   = container.GetBlockBlobReference(this.xmlFilename);
            BlobStream     xmlStream = xmlBlob.OpenWrite();

            // Unzip the backup file
            this.UnzipFile(zipStream, xmlStream);

            // Set delegate to class variable
            this.blockTransfer  = destination.WriteData;
            this.progressChange = progressChange;

            // Open a stream to the xml file
            using (this.inStream = new StreamReader(xmlBlob.OpenRead()))
            {
                // The total number of backup operations is determined by the strem size
                this.TotalOperations = (int)this.inStream.BaseStream.Length;

                // Initialise detination writer
                destination.InitialiseWriting(this.GetTables(this.inStream));

                // Split stream into batches & trigger delegate
                this.BatchStream(this.BlockTranferWithProgressUpdate, this.inStream.BaseStream);

                if (this.Cancelled)
                {
                    // Exit the function if the user has cancelled
                    return;
                }

                // Finalise detination writer
                destination.FinaliseWriting();
            }

            // Delete the xml file
            xmlBlob.Delete();
        }
        public override void TransferData(BackupDataSource destination, ProgressChange progressChange)
        {
            // Get the backup file from blob
            CloudBlockBlob zipBlob = this.container.GetBlockBlobReference(this.filename);
            BlobStream zipStream = zipBlob.OpenRead();

            // Create a temp file for xml file
            CloudBlockBlob xmlBlob = container.GetBlockBlobReference(this.xmlFilename);
            BlobStream xmlStream = xmlBlob.OpenWrite();

            // Unzip the backup file
            this.UnzipFile(zipStream, xmlStream);

            // Set delegate to class variable
            this.blockTransfer = destination.WriteData;
            this.progressChange = progressChange;

            // Open a stream to the xml file
            using (this.inStream = new StreamReader(xmlBlob.OpenRead()))
            {
                // The total number of backup operations is determined by the strem size
                this.TotalOperations = (int)this.inStream.BaseStream.Length;

                // Initialise detination writer
                destination.InitialiseWriting(this.GetTables(this.inStream));

                // Split stream into batches & trigger delegate
                this.BatchStream(this.BlockTranferWithProgressUpdate, this.inStream.BaseStream);

                if (this.Cancelled)
                {
                    // Exit the function if the user has cancelled
                    return;
                }

                // Finalise detination writer
                destination.FinaliseWriting();
            }

            // Delete the xml file
            xmlBlob.Delete();
        }
        /// <summary>
        /// Splits a stream of entites into matches according to Table Service rules.
        /// </summary>
        /// <param name="onBlockRead">The delegate to trigger per batch.</param>
        /// <param name="inStream">The input stream of entities.</param>
        protected void BatchStream(BlockTransfer onBlockRead, Stream inStream)
        {
            using (XmlTextReader reader = new XmlTextReader(inStream))
            {
                MemoryStream outStream = new MemoryStream();
                string batchTableName = null;
                string batchPartitionKey = null;
                string tableName;
                string partitionKey;
                Stream entityStream;
                int entityCount = 0;

                while (reader.Read())
                {
                    if (this.Cancelled)
                    {
                        // Exit the function if the user has cancelled
                        return;
                    }

                    if (reader.Name == "entry" && reader.NodeType == XmlNodeType.Element)
                    {
                        // Get the entity
                        entityStream = this.GetEntity(reader, out tableName, out partitionKey);
                        entityCount++;

                        if (batchTableName == null)
                        {
                            // First entity, so set the first batch table name & partition key
                            batchTableName = tableName;
                            batchPartitionKey = partitionKey;
                        }

                        // Can we add this entity to the current batch?
                        if (entityCount > 100 || // A batch can have a max of 100 transactions
                           (tableName != batchTableName) || // The batch must be within the same table
                           (partitionKey != batchPartitionKey) || // The batch must be within the same partition
                           ((entityStream.Length + outStream.Length) / 1024 > 3800)) // The max payload is 4mb, we make it less to allow for HTTP headers etc
                        {
                            // No, so send current batch to delegate
                            outStream.Position = 0;
                            onBlockRead(batchTableName, outStream);

                            // Reset batch
                            outStream = new MemoryStream();
                            entityCount = 1;
                            batchTableName = tableName;
                            batchPartitionKey = partitionKey;
                        }

                        // Add the entity to the current batch
                        StreamUtil.CopyStream(entityStream, outStream);
                    }
                }

                // Send any remaining entities to delegate
                outStream.Position = 0;
                onBlockRead(batchTableName, outStream);

                // Close the stream
                outStream.Close();
            }
        }
        /// <summary>
        /// Splits a stream of entites into matches according to Table Service rules.
        /// </summary>
        /// <param name="onBlockRead">The delegate to trigger per batch.</param>
        /// <param name="inStream">The input stream of entities.</param>
        protected void BatchStream(BlockTransfer onBlockRead, Stream inStream)
        {
            using (XmlTextReader reader = new XmlTextReader(inStream))
            {
                MemoryStream outStream         = new MemoryStream();
                string       batchTableName    = null;
                string       batchPartitionKey = null;
                string       tableName;
                string       partitionKey;
                Stream       entityStream;
                int          entityCount = 0;

                while (reader.Read())
                {
                    if (this.Cancelled)
                    {
                        // Exit the function if the user has cancelled
                        return;
                    }

                    if (reader.Name == "entry" && reader.NodeType == XmlNodeType.Element)
                    {
                        // Get the entity
                        entityStream = this.GetEntity(reader, out tableName, out partitionKey);
                        entityCount++;

                        if (batchTableName == null)
                        {
                            // First entity, so set the first batch table name & partition key
                            batchTableName    = tableName;
                            batchPartitionKey = partitionKey;
                        }

                        // Can we add this entity to the current batch?
                        if (entityCount > 100 ||                                      // A batch can have a max of 100 transactions
                            (tableName != batchTableName) ||                          // The batch must be within the same table
                            (partitionKey != batchPartitionKey) ||                    // The batch must be within the same partition
                            ((entityStream.Length + outStream.Length) / 1024 > 3800)) // The max payload is 4mb, we make it less to allow for HTTP headers etc
                        {
                            // No, so send current batch to delegate
                            outStream.Position = 0;
                            onBlockRead(batchTableName, outStream);

                            // Reset batch
                            outStream         = new MemoryStream();
                            entityCount       = 1;
                            batchTableName    = tableName;
                            batchPartitionKey = partitionKey;
                        }

                        // Add the entity to the current batch
                        StreamUtil.CopyStream(entityStream, outStream);
                    }
                }

                // Send any remaining entities to delegate
                outStream.Position = 0;
                onBlockRead(batchTableName, outStream);

                // Close the stream
                outStream.Close();
            }
        }