/// <summary>
        /// Uploads one large file to Amazon S3 storage in smaller parts.
        /// </summary>
        /// <remarks>Stream still needs to be disposed.</remarks>
        /// <param name="uploadSessionId">Unique identifier for one multipart upload. Can be obtained by <see cref="M:CMS.AmazonStorage.FileStream.InitMultiPartUpload" /> method.</param>
        /// <param name="partIdentifiers">List of identifiers from Amazon S3 received after uploading each part by <see cref="M:CMS.AmazonStorage.FileStream.UploadStreamContentAsMultiPart(System.String,System.Int32)" /> method.</param>
        /// <returns>ETag of the uploaded file.</returns>
        public string CompleteMultiPartUploadProcess(string uploadSessionId, IEnumerable <string> partIdentifiers)
        {
            this.mMultiPartUploadMode = true;
            List <UploadPartResponse> uploadPartResponseList = partIdentifiers.Select((id, index) => new UploadPartResponse
            {
                PartNumber = index + 1,
                ETag       = id
            }).ToList();

            if (this.obj.IsLocked)
            {
                throw new Exception($"Couldn't upload part of the object {this.obj.Key} because it is used by another process.");
            }
            this.obj.Lock();
            this.obj.ETag = this.MultiPartUploader.CompleteMultiPartUploadProcess(this.obj.Key, this.obj.BucketName, uploadSessionId, uploadPartResponseList).ETag;
            this.obj.UnLock();
            this.SetLastWriteTimeAndCreationTimeToS3Object();
            S3ObjectInfoProvider.RemoveRequestCache(this.obj.Key);
            return(this.obj.ETag);
        }
        /// <summary>
        /// Uploads stream's content to Amazon S3 storage as one part of the file in multipart upload process
        /// identified by <paramref name="uploadSessionId" />.
        /// </summary>
        /// <remarks>
        /// Always returns one ETag in collection. If stream's length is more than 5GB then exception is thrown.
        /// </remarks>
        /// <param name="uploadSessionId">Unique identifier for one multipart upload. Can be obtained by <see cref="M:CMS.AmazonStorage.FileStream.InitMultiPartUpload" />.</param>
        /// <param name="nextPartNumber">Number that defines position of the data obtained by the stream in the whole multipart upload process.</param>
        /// <returns>One unique identifier of the uploaded part in collection.</returns>
        public IEnumerable <string> UploadStreamContentAsMultiPart(string uploadSessionId, int nextPartNumber)
        {
            if (this.Length > this.MaximalPartSize)
            {
                throw new Exception($"Maximal size of part for upload to Amazon S3 storage is {this.MaximalPartSize} current stream has length {this.Length}.");
            }
            this.mMultiPartUploadMode = true;
            if (this.obj.IsLocked)
            {
                throw new Exception($"Couldn't upload part of the object {this.obj.Key} because it is used by another process.");
            }
            this.obj.Lock();
            this.obj.Length += this.Length;
            List <string> stringList = new List <string>();

            this.MultiPartUploader.UploadPartFromStream(uploadSessionId, this.obj.Key, this.obj.BucketName, nextPartNumber, this);
            this.obj.UnLock();
            S3ObjectInfoProvider.RemoveRequestCache(this.obj.Key);
            return(stringList);
        }
 /// <summary>
 /// Aborts multipart upload to Amazon S3 storage and removes all resources already uploaded.
 /// </summary>
 /// <param name="uploadSessionId">
 /// Unique identifier for multipart upload process to external storage.
 /// Is obtained by <see cref="M:CMS.AmazonStorage.FileStream.InitMultiPartUpload" />.
 /// </param>
 public void AbortMultiPartUpload(string uploadSessionId)
 {
     S3ObjectInfoProvider.RemoveRequestCache(this.obj.Key);
     this.MultiPartUploader.AbortMultiPartUpload(this.obj.Key, this.obj.BucketName, uploadSessionId);
 }