public virtual async Task UpdateContentAsync(StorageRecord record, Stream contents, string contentType, IProgress progress, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            GoogleProgressSource uploadProgress = null;
            ProgressReporter     miscProgress   = null;

            if (null != progress)
            {
                uploadProgress = new GoogleProgressSource();
                miscProgress   = new NCoreUtils.Progress.ProgressReporter();
                new SummaryProgress(progress, uploadProgress, miscProgress);
            }
            miscProgress.SetTotal(2);
            miscProgress.SetValue(0);
            long?contentLength;

            try
            {
                contentLength = contents.Length;
            }
            catch (NotSupportedException)
            {
                contentLength = null;
            }
            GoogleObject googleObject;

            if (contentLength.HasValue && contents.CanSeek)
            {
                googleObject = await UpdateSeekableStream(contents, contentLength.Value).ConfigureAwait(false);
            }
            else
            {
                if (string.IsNullOrEmpty(contentType))
                {
                    // if no content length can be deternied and content type is not set --> stream must be buffered....
                    using (var buffer = new MemoryStream())
                    {
                        await contents.CopyToAsync(buffer).ConfigureAwait(false);

                        buffer.Seek(0, SeekOrigin.Begin);
                        googleObject = await UpdateSeekableStream(buffer, buffer.Length);
                    }
                }
                else
                {
                    uploadProgress.SetTotal(1);
                    uploadProgress.SetValue(0);
                    string mediaType = contentType;
                    miscProgress.SetValue(1);
                    var options = new UploadObjectOptions
                    {
                        ChunkSize = StorageProvider.Options.ChunkSize
                    };
                    record.GoogleObject.Crc32c         = null;
                    record.GoogleObject.ComponentCount = null;
                    record.GoogleObject.ETag           = null;
                    record.GoogleObject.Md5Hash        = null;
                    record.GoogleObject.ContentType    = mediaType ?? "application/octet-stream";
                    googleObject = await UseStorageClient(async client =>
                    {
                        record.GoogleObject = await client.UploadObjectAsync(record.GoogleObject, contents, options, cancellationToken).ConfigureAwait(false);
                        miscProgress.SetValue(2);
                        uploadProgress.SetValue(1);
                        return(record.GoogleObject);
                    }).ConfigureAwait(false);
                }
            }
            record.GoogleObject = googleObject;

            async Task <GoogleObject> UpdateSeekableStream(Stream stream, long clength)
            {
                uploadProgress.SetTotal(clength);
                uploadProgress.SetValue(0);
                string mediaType = contentType ?? await StorageProvider.GetMediaTypeAsync(stream, record.Name, cancellationToken).ConfigureAwait(false);

                miscProgress.SetValue(1);
                var options = new UploadObjectOptions
                {
                    ChunkSize = StorageProvider.Options.ChunkSize
                };

                record.GoogleObject.Size           = (ulong)clength;
                record.GoogleObject.Crc32c         = null;
                record.GoogleObject.ComponentCount = null;
                record.GoogleObject.ETag           = null;
                record.GoogleObject.Md5Hash        = null;
                record.GoogleObject.ContentType    = mediaType ?? "application/octet-stream";
                return(await UseStorageClient(async client =>
                {
                    record.GoogleObject = await client.UploadObjectAsync(record.GoogleObject, stream, options, cancellationToken, uploadProgress).ConfigureAwait(false);
                    miscProgress.SetValue(2);
                    return record.GoogleObject;
                }).ConfigureAwait(false));
            }
        }
        public virtual async Task <StorageRecord> CreateRecordAsync(string name, Stream contents, string contentType, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            GoogleProgressSource uploadProgress = null;
            ProgressReporter     miscProgress   = null;

            if (null != progress)
            {
                uploadProgress = new GoogleProgressSource();
                miscProgress   = new NCoreUtils.Progress.ProgressReporter();
                new SummaryProgress(progress, uploadProgress, miscProgress);
            }
            miscProgress.SetTotal(2);
            miscProgress.SetValue(0);
            long?contentLength;

            try
            {
                contentLength = contents.Length;
            }
            catch (NotSupportedException)
            {
                contentLength = null;
            }
            GoogleObject googleObject;

            if (contentLength.HasValue && contents.CanSeek)
            {
                googleObject = await UploadSeekableStream(contents, contentLength.Value);
            }
            else
            {
                if (string.IsNullOrEmpty(contentType))
                {
                    // if no content length can be deternied and content type is not set --> stream must be buffered....
                    using (var buffer = new MemoryStream())
                    {
                        await contents.CopyToAsync(buffer);

                        buffer.Seek(0, SeekOrigin.Begin);
                        googleObject = await UploadSeekableStream(buffer, buffer.Length);
                    }
                }
                else
                {
                    uploadProgress.SetTotal(1);
                    uploadProgress.SetValue(0);
                    var options = new UploadObjectOptions
                    {
                        ChunkSize     = StorageProvider.Options.ChunkSize,
                        PredefinedAcl = StorageProvider.Options.PredefinedAcl
                    };
                    googleObject = new GoogleObject
                    {
                        Bucket             = BucketName,
                        Name               = name.TrimStart('/'),
                        CacheControl       = StorageProvider.Options.DefaultCacheControl,
                        ContentDisposition = StorageProvider.Options.DefaultContentDisposition,
                        ContentEncoding    = StorageProvider.Options.DefaultContentEncoding,
                        ContentLanguage    = StorageProvider.Options.DefaultContentLanguage,
                        ContentType        = contentType
                    };
                    googleObject = await UseStorageClient(client => client.UploadObjectAsync(googleObject, contents, options, cancellationToken)).ConfigureAwait(false);

                    uploadProgress.SetValue(1);
                }
            }
            var result = new StorageRecord(this, name, googleObject);

            miscProgress.SetValue(2);
            return(result);

            async Task <GoogleObject> UploadSeekableStream(Stream stream, long clength)
            {
                uploadProgress.SetTotal(clength);
                uploadProgress.SetValue(0);
                string mediaType;

                if (string.IsNullOrEmpty(contentType))
                {
                    mediaType = await StorageProvider.GetMediaTypeAsync(stream, name, cancellationToken).ConfigureAwait(false);

                    stream.Seek(0, SeekOrigin.Begin);
                }
                else
                {
                    mediaType = contentType;
                }
                miscProgress.SetValue(1);
                var options = new UploadObjectOptions
                {
                    ChunkSize     = StorageProvider.Options.ChunkSize,
                    PredefinedAcl = StorageProvider.Options.PredefinedAcl
                };

                googleObject = new GoogleObject
                {
                    Bucket             = BucketName,
                    Name               = name.TrimStart('/'),
                    CacheControl       = StorageProvider.Options.DefaultCacheControl,
                    ContentDisposition = StorageProvider.Options.DefaultContentDisposition,
                    ContentEncoding    = StorageProvider.Options.DefaultContentEncoding,
                    ContentLanguage    = StorageProvider.Options.DefaultContentLanguage,
                    ContentType        = mediaType ?? "application/octet-stream",
                    Size               = (ulong)clength
                };
                return(await UseStorageClient(client => client.UploadObjectAsync(googleObject, stream, options, cancellationToken, uploadProgress)).ConfigureAwait(false));
            }
        }