コード例 #1
0
 public BlockBlobWriteStream(
     BlockBlobClient blockBlobClient,
     long bufferSize,
     long position,
     BlobRequestConditions conditions,
     IProgress <long> progressHandler,
     BlobHttpHeaders blobHttpHeaders,
     IDictionary <string, string> metadata,
     IDictionary <string, string> tags
     // TODO #27253
     //UploadTransactionalHashingOptions hashingOptions
     ) : base(
         position,
         bufferSize,
         progressHandler
         //hashingOptions
         )
 {
     ValidateBufferSize(bufferSize);
     _blockBlobClient = blockBlobClient;
     _conditions      = conditions ?? new BlobRequestConditions();
     _blockIds        = new List <string>();
     _blobHttpHeaders = blobHttpHeaders;
     _metadata        = metadata;
     _tags            = tags;
 }
コード例 #2
0
        public async Task RenameBlobContainerAsync_SourceLease()
        {
            // Arrange
            BlobServiceClient   service          = GetServiceClient_SharedKey();
            string              oldContainerName = GetNewContainerName();
            string              newContainerName = GetNewContainerName();
            BlobContainerClient container        = InstrumentClient(service.GetBlobContainerClient(oldContainerName));
            await container.CreateAsync();

            string leaseId = Recording.Random.NewGuid().ToString();

            BlobLeaseClient leaseClient = InstrumentClient(container.GetBlobLeaseClient(leaseId));
            await leaseClient.AcquireAsync(duration : TimeSpan.FromSeconds(30));

            BlobRequestConditions sourceConditions = new BlobRequestConditions
            {
                LeaseId = leaseId
            };

            // Act
            BlobContainerClient newContainer = await service.RenameBlobContainerAsync(
                sourceContainerName : oldContainerName,
                destinationContainerName : newContainerName,
                sourceConditions : sourceConditions);

            // Assert
            await newContainer.GetPropertiesAsync();

            // Cleanup
            await newContainer.DeleteAsync();
        }
コード例 #3
0
        public async Task RenameBlobContainerAsync_SourceLeaseFailed()
        {
            // Arrange
            BlobServiceClient   service          = GetServiceClient_SharedKey();
            string              oldContainerName = GetNewContainerName();
            string              newContainerName = GetNewContainerName();
            BlobContainerClient container        = InstrumentClient(service.GetBlobContainerClient(oldContainerName));
            await container.CreateAsync();

            string leaseId = Recording.Random.NewGuid().ToString();

            BlobRequestConditions sourceConditions = new BlobRequestConditions
            {
                LeaseId = leaseId
            };

            // Act
            await TestHelper.AssertExpectedExceptionAsync <RequestFailedException>(
                service.RenameBlobContainerAsync(
                    sourceContainerName: oldContainerName,
                    destinationContainerName: newContainerName,
                    sourceConditions: sourceConditions),
                e => Assert.AreEqual(BlobErrorCode.LeaseNotPresentWithContainerOperation.ToString(), e.ErrorCode));

            // Cleanup
            await container.DeleteAsync();
        }
コード例 #4
0
        public async Task QueryAsync_AccessConditionsFail()
        {
            var garbageLeaseId = GetGarbageLeaseId();

            foreach (AccessConditionParameters parameters in GetAccessConditionsFail_Data(garbageLeaseId))
            {
                // Arrange
                await using DisposingContainer test = await GetTestContainerAsync();

                BlockBlobClient blockBlobClient = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName()));
                Stream          stream          = CreateDataStream(Constants.KB);
                await blockBlobClient.UploadAsync(stream);

                parameters.NoneMatch = await SetupBlobMatchCondition(blockBlobClient, parameters.NoneMatch);

                BlobRequestConditions accessConditions = BuildAccessConditions(parameters);
                BlobQueryOptions      options          = new BlobQueryOptions
                {
                    Conditions = accessConditions
                };

                string query = @"SELECT * from BlobStorage";

                // Act
                await TestHelper.AssertExpectedExceptionAsync <RequestFailedException>(
                    blockBlobClient.QueryAsync(
                        query,
                        options),
                    e => { });
            }
        }
コード例 #5
0
        public async Task SetImmutibilityPolicyAsync_IfModifiedSince()
        {
            // Arrange
            BlobBaseClient blob = await GetNewBlobClient(_containerClient);

            BlobImmutabilityPolicy immutabilityPolicy = new BlobImmutabilityPolicy
            {
                ExpiresOn  = Recording.UtcNow.AddMinutes(5),
                PolicyMode = BlobImmutabilityPolicyMode.Unlocked
            };

            // The service rounds Immutability Policy Expiry to the nearest second.
            DateTimeOffset expectedImmutabilityPolicyExpiry = RoundToNearestSecond(immutabilityPolicy.ExpiresOn.Value);

            BlobRequestConditions conditions = new BlobRequestConditions
            {
                IfUnmodifiedSince = Recording.UtcNow.AddDays(1)
            };

            // Act
            Response <BlobImmutabilityPolicy> response = await blob.SetImmutabilityPolicyAsync(
                immutabilityPolicy : immutabilityPolicy,
                conditions : conditions);

            // Assert
            Assert.AreEqual(expectedImmutabilityPolicyExpiry, response.Value.ExpiresOn);
            Assert.AreEqual(immutabilityPolicy.PolicyMode, response.Value.PolicyMode);
        }
コード例 #6
0
        public override async Task <OriginalData> GetAsync(string source, ICachedImage existingCachedImage)
        {
            BlobClient blob = Client.GetBlobClient(source);

            BlobRequestConditions conditions = new BlobRequestConditions();

            if (existingCachedImage != null)
            {
                conditions.IfNoneMatch = new ETag(existingCachedImage.Metadata.Cache.ETag);
            }

            var response = await blob.DownloadAsync(conditions : conditions);

            if (response.GetRawResponse().Status == (int)System.Net.HttpStatusCode.NotModified)
            {
                return(null);
            }

            return(new OriginalData(
                       response.Value.ContentType,
                       await response.Value.Content.ToByteArrayAsync(),
                       new CacheSettings()
            {
                ETag = response.Value.Details.ETag.ToString().GetTagUnquoted()
            }));
        }
コード例 #7
0
 public virtual async Task <Response <BlobContentInfo> > UploadAsync(
     string path,
     BlobHttpHeaders httpHeaders            = default,
     Metadata metadata                      = default,
     BlobRequestConditions conditions       = default,
     IProgress <long> progressHandler       = default,
     AccessTier?accessTier                  = default,
     StorageTransferOptions transferOptions = default,
     CancellationToken cancellationToken    = default)
 {
     using (FileStream stream = new FileStream(path, FileMode.Open))
     {
         return(await StagedUploadAsync(
                    stream,
                    httpHeaders,
                    metadata,
                    conditions,
                    progressHandler,
                    accessTier,
                    transferOptions : transferOptions,
                    async : true,
                    cancellationToken : cancellationToken)
                .ConfigureAwait(false));
     }
 }
コード例 #8
0
        /// <summary>
        /// This operation will create a new
        /// block blob of arbitrary size by uploading it as indiviually staged
        /// blocks if it's larger than the
        /// <paramref name="singleUploadThreshold"/>.
        /// </summary>
        /// <param name="content">
        /// A <see cref="Stream"/> containing the content to upload.
        /// </param>
        /// <param name="blobHttpHeaders">
        /// Optional standard HTTP header properties that can be set for the
        /// block blob.
        /// </param>
        /// <param name="metadata">
        /// Optional custom metadata to set for this block blob.
        /// </param>
        /// <param name="conditions">
        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
        /// the creation of this new block blob.
        /// </param>
        /// <param name="progressHandler">
        /// Optional <see cref="IProgress{Long}"/> to provide
        /// progress updates about data transfers.
        /// </param>
        /// <param name="accessTier">
        /// Optional <see cref="AccessTier"/>
        /// Indicates the tier to be set on the blob.
        /// </param>
        /// <param name="singleUploadThreshold">
        /// The maximum size stream that we'll upload as a single block.  The
        /// default value is 256MB.
        /// </param>
        /// <param name="transferOptions">
        /// Optional <see cref="StorageTransferOptions"/> to configure
        /// parallel transfer behavior.
        /// </param>
        /// <param name="async">
        /// </param>
        /// <param name="cancellationToken">
        /// Optional <see cref="CancellationToken"/> to propagate
        /// notifications that the operation should be cancelled.
        /// </param>
        /// <returns>
        /// A <see cref="Response{BlobContentInfo}"/> describing the
        /// state of the updated block blob.
        /// </returns>
        /// <remarks>
        /// A <see cref="RequestFailedException"/> will be thrown if
        /// a failure occurs.
        /// </remarks>
        internal async Task <Response <BlobContentInfo> > StagedUploadAsync(
            Stream content,
            BlobHttpHeaders blobHttpHeaders,
            Metadata metadata,
            BlobRequestConditions conditions,
            IProgress <long> progressHandler,
            AccessTier?accessTier                  = default,
            long?singleUploadThreshold             = default,
            StorageTransferOptions transferOptions = default,
            bool async = true,
            CancellationToken cancellationToken = default)
        {
            var client = new BlockBlobClient(Uri, Pipeline, ClientDiagnostics, CustomerProvidedKey);

            singleUploadThreshold ??= client.BlockBlobMaxUploadBlobBytes;
            Debug.Assert(singleUploadThreshold <= client.BlockBlobMaxUploadBlobBytes);

            var uploader = new PartitionedUploader(client, transferOptions, singleUploadThreshold);

            if (async)
            {
                return(await uploader.UploadAsync(content, blobHttpHeaders, metadata, conditions, progressHandler, accessTier, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                return(uploader.Upload(content, blobHttpHeaders, metadata, conditions, progressHandler, accessTier, cancellationToken));
            }
        }
コード例 #9
0
 /// <summary>
 /// This operation will create a new
 /// block blob of arbitrary size by uploading it as indiviually staged
 /// blocks if it's larger than the
 /// <paramref name="singleUploadThreshold"/>.
 /// </summary>
 /// <param name="path">
 /// A file path of the file to upload.
 /// </param>
 /// <param name="blobHttpHeaders">
 /// Optional standard HTTP header properties that can be set for the
 /// block blob.
 /// </param>
 /// <param name="metadata">
 /// Optional custom metadata to set for this block blob.
 /// </param>
 /// <param name="conditions">
 /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 /// the creation of this new block blob.
 /// </param>
 /// <param name="progressHandler">
 /// Optional <see cref="IProgress{Long}"/> to provide
 /// progress updates about data transfers.
 /// </param>
 /// <param name="accessTier">
 /// Optional <see cref="AccessTier"/>
 /// Indicates the tier to be set on the blob.
 /// </param>
 /// <param name="singleUploadThreshold">
 /// The maximum size stream that we'll upload as a single block.  The
 /// default value is 256MB.
 /// </param>
 /// <param name="transferOptions">
 /// Optional <see cref="StorageTransferOptions"/> to configure
 /// parallel transfer behavior.
 /// </param>
 /// <param name="async">
 /// </param>
 /// <param name="cancellationToken">
 /// Optional <see cref="CancellationToken"/> to propagate
 /// notifications that the operation should be cancelled.
 /// </param>
 /// <returns>
 /// A <see cref="Response{BlobContentInfo}"/> describing the
 /// state of the updated block blob.
 /// </returns>
 /// <remarks>
 /// A <see cref="RequestFailedException"/> will be thrown if
 /// a failure occurs.
 /// </remarks>
 internal async Task <Response <BlobContentInfo> > StagedUploadAsync(
     string path,
     BlobHttpHeaders blobHttpHeaders,
     Metadata metadata,
     BlobRequestConditions conditions,
     IProgress <long> progressHandler,
     AccessTier?accessTier                  = default,
     long?singleUploadThreshold             = default,
     StorageTransferOptions transferOptions = default,
     bool async = true,
     CancellationToken cancellationToken = default)
 {
     using (FileStream stream = new FileStream(path, FileMode.Open))
     {
         return(await StagedUploadAsync(
                    stream,
                    blobHttpHeaders,
                    metadata,
                    conditions,
                    progressHandler,
                    accessTier,
                    singleUploadThreshold : singleUploadThreshold,
                    transferOptions : transferOptions,
                    async : async,
                    cancellationToken : cancellationToken)
                .ConfigureAwait(false));
     }
 }
コード例 #10
0
        /// <summary>
        /// This operation will create a new
        /// block blob of arbitrary size by uploading it as indiviually staged
        /// blocks if it's larger than the
        /// <paramref name="transferOptions"/> MaximumTransferLength.
        /// </summary>
        /// <param name="content">
        /// A <see cref="Stream"/> containing the content to upload.
        /// </param>
        /// <param name="blobHttpHeaders">
        /// Optional standard HTTP header properties that can be set for the
        /// block blob.
        /// </param>
        /// <param name="metadata">
        /// Optional custom metadata to set for this block blob.
        /// </param>
        /// <param name="conditions">
        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
        /// the creation of this new block blob.
        /// </param>
        /// <param name="progressHandler">
        /// Optional <see cref="IProgress{Long}"/> to provide
        /// progress updates about data transfers.
        /// </param>
        /// <param name="accessTier">
        /// Optional <see cref="AccessTier"/>
        /// Indicates the tier to be set on the blob.
        /// </param>
        /// <param name="transferOptions">
        /// Optional <see cref="StorageTransferOptions"/> to configure
        /// parallel transfer behavior.
        /// </param>
        /// <param name="async">
        /// </param>
        /// <param name="cancellationToken">
        /// Optional <see cref="CancellationToken"/> to propagate
        /// notifications that the operation should be cancelled.
        /// </param>
        /// <returns>
        /// A <see cref="Response{BlobContentInfo}"/> describing the
        /// state of the updated block blob.
        /// </returns>
        /// <remarks>
        /// A <see cref="RequestFailedException"/> will be thrown if
        /// a failure occurs.
        /// </remarks>
        internal async Task <Response <BlobContentInfo> > StagedUploadAsync(
            Stream content,
            BlobHttpHeaders blobHttpHeaders,
            Metadata metadata,
            BlobRequestConditions conditions,
            IProgress <long> progressHandler,
            AccessTier?accessTier = default,
            StorageTransferOptions transferOptions = default,
            bool async = true,
            CancellationToken cancellationToken = default)
        {
            if (UsingClientSideEncryption)
            {
                // content is now unseekable, so PartitionedUploader will be forced to do a buffered multipart upload
                (content, metadata) = await new BlobClientSideEncryptor(new ClientSideEncryptor(ClientSideEncryption))
                                      .ClientSideEncryptInternal(content, metadata, async, cancellationToken).ConfigureAwait(false);
            }

            var client = new BlockBlobClient(Uri, Pipeline, Version, ClientDiagnostics, CustomerProvidedKey, EncryptionScope);

            PartitionedUploader uploader = new PartitionedUploader(
                client,
                transferOptions,
                operationName: $"{nameof(BlobClient)}.{nameof(Upload)}");

            if (async)
            {
                return(await uploader.UploadAsync(content, blobHttpHeaders, metadata, conditions, progressHandler, accessTier, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                return(uploader.Upload(content, blobHttpHeaders, metadata, conditions, progressHandler, accessTier, cancellationToken));
            }
        }
コード例 #11
0
 /// <summary>
 /// The <see cref="Upload(string, BlobHttpHeaders, Metadata, BlobRequestConditions, IProgress{long}, AccessTier?, StorageTransferOptions, CancellationToken)"/>
 /// operation creates a new block blob or updates the content of an
 /// existing block blob.  Updating an existing block blob overwrites
 /// any existing metadata on the blob.
 ///
 /// For partial block blob updates and other advanced features, please
 /// see <see cref="BlockBlobClient"/>.  To create or modify page or
 /// append blobs, please see <see cref="PageBlobClient"/> or
 /// <see cref="AppendBlobClient"/>.
 ///
 /// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob" />.
 /// </summary>
 /// <param name="path">
 /// A file path containing the content to upload.
 /// </param>
 /// <param name="httpHeaders">
 /// Optional standard HTTP header properties that can be set for the
 /// block blob.
 /// </param>
 /// <param name="metadata">
 /// Optional custom metadata to set for this block blob.
 /// </param>
 /// <param name="conditions">
 /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 /// the creation of this new block blob.
 /// </param>
 /// <param name="progressHandler">
 /// Optional <see cref="IProgress{Long}"/> to provide
 /// progress updates about data transfers.
 /// </param>
 /// <param name="accessTier">
 /// Optional <see cref="AccessTier"/>
 /// Indicates the tier to be set on the blob.
 /// </param>
 /// <param name="transferOptions">
 /// Optional <see cref="StorageTransferOptions"/> to configure
 /// parallel transfer behavior.
 /// </param>
 /// <param name="cancellationToken">
 /// Optional <see cref="CancellationToken"/> to propagate
 /// notifications that the operation should be cancelled.
 /// </param>
 /// <returns>
 /// A <see cref="Response{BlobContentInfo}"/> describing the
 /// state of the updated block blob.
 /// </returns>
 /// <remarks>
 /// A <see cref="RequestFailedException"/> will be thrown if
 /// a failure occurs.
 /// </remarks>
 public virtual Response <BlobContentInfo> Upload(
     string path,
     BlobHttpHeaders httpHeaders            = default,
     Metadata metadata                      = default,
     BlobRequestConditions conditions       = default,
     IProgress <long> progressHandler       = default,
     AccessTier?accessTier                  = default,
     StorageTransferOptions transferOptions = default,
     CancellationToken cancellationToken    = default)
 {
     using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
     {
         return(StagedUploadAsync(
                    stream,
                    httpHeaders,
                    metadata,
                    conditions,
                    progressHandler,
                    accessTier,
                    transferOptions: transferOptions,
                    async: false,
                    cancellationToken: cancellationToken)
                .EnsureCompleted());
     }
 }
コード例 #12
0
 private static BlobRequestConditions CreateConditionsWithEtag(BlobRequestConditions conditions, ETag etag) =>
 new BlobRequestConditions
 {
     LeaseId           = conditions?.LeaseId,
     IfMatch           = conditions?.IfMatch ?? etag,
     IfNoneMatch       = conditions?.IfNoneMatch,
     IfModifiedSince   = conditions?.IfModifiedSince,
     IfUnmodifiedSince = conditions?.IfUnmodifiedSince
 };
コード例 #13
0
        public AzureWriteBlockBlobStream(BlockBlobClient blob, BlobRequestConditions condition, IDictionary <string, string> metadata)
        {
            _blob      = blob;
            _condition = condition;
            _metadata  = metadata;

            _buff       = new MemoryStream();
            _partNumber = 1;
        }
コード例 #14
0
 protected override Task <Stream> OpenWriteAsync(
     AppendBlobClient client,
     bool overwrite,
     long?maxDataSize,
     int?bufferSize = null,
     BlobRequestConditions conditions     = null,
     Dictionary <string, string> metadata = null,
     HttpHeaderParameters httpHeaders     = null,
     IProgress <long> progressHandler     = null)
 => OpenWriteAsync(client, overwrite, maxDataSize, tags: default, bufferSize, conditions, metadata, httpHeaders, progressHandler);
コード例 #15
0
 /// <summary>
 /// Calls this client's open-write method.
 /// </summary>
 /// <param name="client">Client to call the download on.</param>
 protected abstract Task <Stream> OpenWriteAsync(
     TBlobClient client,
     bool overwrite,
     long?maxDataSize,
     Dictionary <string, string> tags,
     int?bufferSize = default,
     BlobRequestConditions conditions     = default,
     Dictionary <string, string> metadata = default,
     HttpHeaderParameters httpHeaders     = default,
     IProgress <long> progressHandler     = default);
コード例 #16
0
 /// <summary>
 /// Rotates the Key Encryption Key (KEK) for a client-side encrypted blob without
 /// needing to reupload the entire blob.
 /// </summary>
 /// <param name="client">
 /// Client to the blob.
 /// </param>
 /// <param name="encryptionOptionsOverride">
 /// Optional override for client-side encryption options to use when updating the key encryption key.
 /// Defaults to the <see cref="ClientSideEncryptionOptions"/> configured on the client when this is
 /// not populated. New key encryption key for the blob will be the
 /// <see cref="ClientSideEncryptionOptions.KeyEncryptionKey"/> on whichever encryption options are
 /// used for the operation. Options must have a resolver that can resolve the old key on the blob.
 /// </param>
 /// <param name="conditions">
 /// Optional request conditions for the operation.
 /// </param>
 /// <param name="cancellationToken">
 /// Cancellation token for the operation.
 /// </param>
 public static void UpdateClientSideKeyEncryptionKey(
     this BlobClient client,
     ClientSideEncryptionOptions encryptionOptionsOverride = default,
     BlobRequestConditions conditions    = default,
     CancellationToken cancellationToken = default)
 => UpdateClientsideKeyEncryptionKeyInternal(
     client,
     encryptionOptionsOverride,
     conditions,
     async: false,
     cancellationToken).EnsureCompleted();
コード例 #17
0
        public async ValueTask <IDictionary <string, string> > GetMetadataAsync(string leaseId, CancellationToken cancellationToken)
        {
            var conditions = new BlobRequestConditions {
                LeaseId = leaseId
            };
            var properties = SyncViaAsync.IsSynchronous
                ? this._blobClient.GetProperties(conditions, cancellationToken)
                : await this._blobClient.GetPropertiesAsync(conditions, cancellationToken).ConfigureAwait(false);

            return(properties.Value.Metadata);
        }
コード例 #18
0
 /// <summary>
 /// Rotates the Key Encryption Key (KEK) for a client-side encrypted blob without
 /// needing to reupload the entire blob.
 /// </summary>
 /// <param name="client">
 /// Client to the blob.
 /// </param>
 /// <param name="encryptionOptionsOverride">
 /// Optional override for client-side encryption options to use when updating the key encryption key.
 /// Defaults to the <see cref="ClientSideEncryptionOptions"/> configured on the client when this is
 /// not populated. New key encryption key for the blob will be the
 /// <see cref="ClientSideEncryptionOptions.KeyEncryptionKey"/> on whichever encryption options are
 /// used for the operation. Options must have a resolver that can resolve the old key on the blob.
 /// </param>
 /// <param name="conditions">
 /// Optional request conditions for the operation.
 /// </param>
 /// <param name="cancellationToken">
 /// Cancellation token for the operation.
 /// </param>
 public static async Task UpdateClientSideKeyEncryptionKeyAsync(
     this BlobClient client,
     ClientSideEncryptionOptions encryptionOptionsOverride = default,
     BlobRequestConditions conditions    = default,
     CancellationToken cancellationToken = default)
 => await UpdateClientsideKeyEncryptionKeyInternal(
     client,
     encryptionOptionsOverride,
     conditions,
     async : true,
     cancellationToken).ConfigureAwait(false);
コード例 #19
0
        /// <summary>
        /// The <see cref="DeleteBlob(Uri, DeleteSnapshotsOption, BlobRequestConditions)"/>
        /// operation marks the specified blob or snapshot for deletion. The
        /// blob is later deleted during garbage collection.
        ///
        /// Note that in order to delete a blob, you must delete all of its
        /// snapshots. You can delete both at the same time using
        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
        ///
        /// For more information, see
        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">Delete Blob</see>.
        /// </summary>
        /// <param name="blobUri">
        /// The blob to delete's primary <see cref="Uri"/> endpoint.
        /// </param>
        /// <param name="snapshotsOption">
        /// Specifies options for deleting blob snapshots.
        /// </param>
        /// <param name="conditions">
        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
        /// deleting this blob.
        /// </param>
        /// <returns>
        /// A <see cref="Response"/> on successfully deleting.  The response
        /// cannot be used until the batch has been submitted with
        /// <see cref="BlobBatchClient.SubmitBatchAsync"/>.
        /// </returns>
        public virtual Response DeleteBlob(
            Uri blobUri,
            DeleteSnapshotsOption snapshotsOption = default,
            BlobRequestConditions conditions      = default)
        {
            BlobUriBuilder uriBuilder = new BlobUriBuilder(blobUri);

            return(DeleteBlob(
                       blobContainerName: uriBuilder.BlobContainerName,
                       blobName: uriBuilder.BlobName,
                       snapshotsOption: snapshotsOption,
                       conditions: conditions));
        }
コード例 #20
0
        /// <summary>
        ///   Updates the checkpoint using the given information for the associated partition and consumer group in the storage blob service.
        /// </summary>
        ///
        /// <param name="checkpoint">The checkpoint containing the information to be stored.</param>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        ///
        public override async Task UpdateCheckpointAsync(Checkpoint checkpoint)
        {
            var        blobName   = $"{ checkpoint.FullyQualifiedNamespace }/{ checkpoint.EventHubName }/{ checkpoint.ConsumerGroup }/{ checkpoint.PartitionId }";
            BlobClient blobClient = _containerClient.GetBlobClient(blobName);

            BlobProperties currentBlob;

            try
            {
                currentBlob = (await blobClient.GetPropertiesAsync().ConfigureAwait(false)).Value;
            }
            catch (RequestFailedException ex) when(ex.ErrorCode == BlobErrorCode.BlobNotFound)
            {
                Log($"Checkpoint with partition id = '{ checkpoint.PartitionId }' could not be updated because no associated ownership was found.");
                return;
            }

            // In case this key does not exist, ownerIdentifier is set to null.  The OwnerIdentifier in Checkpoint cannot
            // be null as well, so we won't be able to update the associated ownership.

            currentBlob.Metadata.TryGetValue(BlobMetadataKey.OwnerIdentifier, out var ownerIdentifier);

            if (ownerIdentifier == checkpoint.OwnerIdentifier)
            {
                var metadata = new Dictionary <string, string>()
                {
                    { BlobMetadataKey.OwnerIdentifier, checkpoint.OwnerIdentifier },
                    { BlobMetadataKey.Offset, checkpoint.Offset.ToString() },
                    { BlobMetadataKey.SequenceNumber, checkpoint.SequenceNumber.ToString() }
                };

                var requestConditions = new BlobRequestConditions {
                    IfMatch = currentBlob.ETag
                };

                try
                {
                    await blobClient.SetMetadataAsync(metadata, requestConditions).ConfigureAwait(false);

                    Log($"Checkpoint with partition id = '{ checkpoint.PartitionId }' updated.");
                }
                catch (RequestFailedException ex) when(ex.ErrorCode == BlobErrorCode.ConditionNotMet)
                {
                    Log($"Checkpoint with partition id = '{ checkpoint.PartitionId }' could not be updated because eTag has changed.");
                }
            }
            else
            {
                Log($"Checkpoint with partition id = '{ checkpoint.PartitionId }' could not be updated because owner has changed.");
            }
        }
コード例 #21
0
            public override Task <Response <BlobProperties> > GetPropertiesAsync(BlobRequestConditions conditions = null, CancellationToken cancellationToken = default)
            {
                if (GetPropertiesException != null)
                {
                    throw GetPropertiesException;
                }

                if (Properties == null)
                {
                    throw new RequestFailedException(404, BlobErrorCode.BlobNotFound.ToString(), BlobErrorCode.BlobNotFound.ToString(), default);
                }

                return(Task.FromResult(Response.FromValue(Properties, Mock.Of <Response>())));
            }
コード例 #22
0
 public BlockBlobWriteStream(
     BlockBlobClient blockBlobClient,
     long bufferSize,
     long position,
     BlobRequestConditions conditions,
     IProgress <long> progressHandler) : base(
         position,
         bufferSize,
         progressHandler)
 {
     ValidateBufferSize(bufferSize);
     _blockBlobClient = blockBlobClient;
     _conditions      = conditions ?? new BlobRequestConditions();
     _blockIds        = new List <string>();
 }
コード例 #23
0
        /// <summary>
        /// The <see cref="SetBlobAccessTier(Uri, AccessTier, RehydratePriority?, BlobRequestConditions)"/>
        /// operation sets the tier on a blob.  The operation is allowed on
        /// block blobs in a blob storage or general purpose v2 account.
        ///
        /// A block blob's tier determines Hot/Cool/Archive storage type.  This
        /// operation does not update the blob's ETag.  For detailed
        /// information about block blob level tiering
        /// <see href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers">
        /// Blob Storage Tiers</see>.
        ///
        /// </summary>
        /// <param name="blobUri">
        /// The blob's primary <see cref="Uri"/> endpoint.
        /// </param>
        /// <param name="accessTier">
        /// Indicates the tier to be set on the blob.
        /// </param>
        /// <param name="rehydratePriority">
        /// Optional <see cref="RehydratePriority"/>
        /// Indicates the priority with which to rehydrate an archived blob.
        /// </param>
        /// <param name="leaseAccessConditions">
        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
        /// setting the access tier.
        /// </param>
        /// <returns>
        /// A <see cref="Response"/> on successfully deleting.  The response
        /// cannot be used until the batch has been submitted with
        /// <see cref="BlobBatchClient.SubmitBatchAsync"/>.
        /// </returns>
        public virtual Response SetBlobAccessTier(
            Uri blobUri,
            AccessTier accessTier,
            RehydratePriority?rehydratePriority         = default,
            BlobRequestConditions leaseAccessConditions = default)
        {
            BlobUriBuilder uriBuilder = new BlobUriBuilder(blobUri);

            return(SetBlobAccessTier(
                       blobContainerName: uriBuilder.BlobContainerName,
                       blobName: uriBuilder.BlobName,
                       accessTier: accessTier,
                       rehydratePriority: rehydratePriority,
                       leaseAccessConditions: leaseAccessConditions));
        }
コード例 #24
0
        /// <summary>
        /// This operation will create a new
        /// block blob of arbitrary size by uploading it as indiviually staged
        /// blocks if it's larger than the
        /// <paramref name="transferOptions"/>. MaximumTransferLength.
        /// </summary>
        /// <param name="path">
        /// A file path of the file to upload.
        /// </param>
        /// <param name="blobHttpHeaders">
        /// Optional standard HTTP header properties that can be set for the
        /// block blob.
        /// </param>
        /// <param name="metadata">
        /// Optional custom metadata to set for this block blob.
        /// </param>
        /// <param name="conditions">
        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
        /// the creation of this new block blob.
        /// </param>
        /// <param name="progressHandler">
        /// Optional <see cref="IProgress{Long}"/> to provide
        /// progress updates about data transfers.
        /// </param>
        /// <param name="accessTier">
        /// Optional <see cref="AccessTier"/>
        /// Indicates the tier to be set on the blob.
        /// </param>
        /// <param name="transferOptions">
        /// Optional <see cref="StorageTransferOptions"/> to configure
        /// parallel transfer behavior.
        /// </param>
        /// <param name="async">
        /// </param>
        /// <param name="cancellationToken">
        /// Optional <see cref="CancellationToken"/> to propagate
        /// notifications that the operation should be cancelled.
        /// </param>
        /// <returns>
        /// A <see cref="Response{BlobContentInfo}"/> describing the
        /// state of the updated block blob.
        /// </returns>
        /// <remarks>
        /// A <see cref="RequestFailedException"/> will be thrown if
        /// a failure occurs.
        /// </remarks>
        internal async Task <Response <BlobContentInfo> > StagedUploadAsync(
            string path,
            BlobHttpHeaders blobHttpHeaders,
            Metadata metadata,
            BlobRequestConditions conditions,
            IProgress <long> progressHandler,
            AccessTier?accessTier = default,
            StorageTransferOptions transferOptions = default,
            bool async = true,
            CancellationToken cancellationToken = default)
        {
            // TODO Upload from file will get it's own implementation in the future that opens more
            //      than one stream at once. This is incompatible with .NET's CryptoStream. We will
            //      need to uncomment the below code and revert to upload from stream if client-side
            //      encryption is enabled.
            //if (ClientSideEncryption != default)
            //{
            //    using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
            //    {
            //        return await StagedUploadAsync(
            //            stream,
            //            blobHttpHeaders,
            //            metadata,
            //            conditions,
            //            progressHandler,
            //            accessTier,
            //            transferOptions: transferOptions,
            //            async: async,
            //            cancellationToken: cancellationToken)
            //            .ConfigureAwait(false);
            //    }
            //}

            using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                return(await StagedUploadAsync(
                           stream,
                           blobHttpHeaders,
                           metadata,
                           conditions,
                           progressHandler,
                           accessTier,
                           transferOptions : transferOptions,
                           async : async,
                           cancellationToken : cancellationToken)
                       .ConfigureAwait(false));
            }
        }
コード例 #25
0
        public async Task SetImmutibilityPolicyAsync_InvalidRequestConditions(string invalidCondition)
        {
            // Arrange
            BlobBaseClient blobBaseClient = new BlobBaseClient(new Uri("https://www.doesntmatter.com"), GetOptions());

            BlobImmutabilityPolicy immutabilityPolicy = new BlobImmutabilityPolicy
            {
                ExpiresOn  = Recording.UtcNow.AddMinutes(5),
                PolicyMode = BlobImmutabilityPolicyMode.Unlocked
            };

            BlobRequestConditions conditions = new BlobRequestConditions();

            switch (invalidCondition)
            {
            case nameof(BlobRequestConditions.IfMatch):
                conditions.IfMatch = new ETag();
                break;

            case nameof(BlobRequestConditions.IfModifiedSince):
                conditions.IfModifiedSince = Recording.UtcNow.AddMinutes(5);
                break;

            case nameof(BlobRequestConditions.IfNoneMatch):
                conditions.IfNoneMatch = new ETag();
                break;

            case nameof(BlobRequestConditions.LeaseId):
                conditions.LeaseId = string.Empty;
                break;

            case nameof(BlobRequestConditions.TagConditions):
                conditions.TagConditions = string.Empty;
                break;
            }

            // Act
            await TestHelper.AssertExpectedExceptionAsync <ArgumentException>(
                blobBaseClient.SetImmutabilityPolicyAsync(
                    immutabilityPolicy,
                    conditions),
                e =>
            {
                Assert.IsTrue(e.Message.Contains($"SetImmutabilityPolicy does not support the {invalidCondition} condition(s)."));
                Assert.IsTrue(e.Message.Contains("conditions"));
            });
        }
コード例 #26
0
        public Response <BlobContentInfo> Upload(
            Stream content,
            BlobHttpHeaders blobHttpHeaders,
            IDictionary <string, string> metadata,
            BlobRequestConditions conditions,
            IProgress <long> progressHandler,
            AccessTier?accessTier = default,
            CancellationToken cancellationToken = default)
        {
            // If we can compute the size and it's small enough
            if (PartitionedUploadExtensions.TryGetLength(content, out long length) && length < _singleUploadThreshold)
            {
                // Upload it in a single request
                return(_client.UploadInternal(
                           content,
                           blobHttpHeaders,
                           metadata,
                           conditions,
                           accessTier,
                           progressHandler,
                           _operationName,
                           false,
                           cancellationToken).EnsureCompleted());
            }

            // If the caller provided an explicit block size, we'll use it.
            // Otherwise we'll adjust dynamically based on the size of the
            // content.
            int blockSize =
                _blockSize != null ? _blockSize.Value :
                length < Constants.LargeUploadThreshold ?
                Constants.DefaultBufferSize :
                Constants.LargeBufferSize;

            // Otherwise stage individual blocks one at a time.  It's not as
            // fast as a parallel upload, but you get the benefit of the retry
            // policy working on a single block instead of the entire stream.
            return(UploadInSequence(
                       content,
                       blockSize,
                       blobHttpHeaders,
                       metadata,
                       conditions,
                       progressHandler,
                       accessTier,
                       cancellationToken));
        }
コード例 #27
0
        public async Task <Response <BlobContentInfo> > UploadAsync(
            Stream content,
            BlobHttpHeaders blobHttpHeaders,
            IDictionary <string, string> metadata,
            BlobRequestConditions conditions,
            IProgress <long> progressHandler,
            AccessTier?accessTier = default,
            CancellationToken cancellationToken = default)
        {
            // If we can compute the size and it's small enough
            if (PartitionedUploadExtensions.TryGetLength(content, out long length) && length < _singleUploadThreshold)
            {
                // Upload it in a single request
                return(await _client.UploadInternal(
                           content,
                           blobHttpHeaders,
                           metadata,
                           conditions,
                           accessTier,
                           progressHandler,
                           _operationName,
                           async : true,
                           cancellationToken)
                       .ConfigureAwait(false));
            }

            // If the caller provided an explicit block size, we'll use it.
            // Otherwise we'll adjust dynamically based on the size of the
            // content.
            int blockSize =
                _blockSize != null ? _blockSize.Value :
                length < Constants.LargeUploadThreshold ?
                Constants.DefaultBufferSize :
                Constants.LargeBufferSize;

            // Otherwise stage individual blocks in parallel
            return(await UploadInParallelAsync(
                       content,
                       blockSize,
                       blobHttpHeaders,
                       metadata,
                       conditions,
                       progressHandler,
                       accessTier,
                       cancellationToken)
                   .ConfigureAwait(false));
        }
コード例 #28
0
        /// <summary>
        /// The <see cref="DeleteBlob(string, string, DeleteSnapshotsOption, BlobRequestConditions)"/>
        /// operation marks the specified blob or snapshot for  deletion. The
        /// blob is later deleted during garbage collection.
        ///
        /// Note that in order to delete a blob, you must delete all of its
        /// snapshots. You can delete both at the same time using
        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
        ///
        /// For more information, see
        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">Delete Blob</see>.
        /// </summary>
        /// <param name="blobContainerName">
        /// The name of the container containing the blob to delete.
        /// </param>
        /// <param name="blobName">
        /// The name of the blob to delete.
        /// </param>
        /// <param name="snapshotsOption">
        /// Specifies options for deleting blob snapshots.
        /// </param>
        /// <param name="conditions">
        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
        /// deleting this blob.
        /// </param>
        /// <returns>
        /// A <see cref="Response"/> on successfully deleting.  The response
        /// cannot be used until the batch has been submitted with
        /// <see cref="BlobBatchClient.SubmitBatchAsync"/>.
        /// </returns>
        public virtual Response DeleteBlob(
            string blobContainerName,
            string blobName,
            DeleteSnapshotsOption snapshotsOption = default,
            BlobRequestConditions conditions      = default)
        {
            var blobUri = new BlobUriBuilder(_client.Uri)
            {
                BlobContainerName = blobContainerName,
                BlobName          = blobName
            };

            return(DeleteBlob(
                       blobUri.ToUri(),
                       snapshotsOption,
                       conditions));
        }
コード例 #29
0
        public void StoreCreatesBlobWhenNotExist()
        {
            BlobRequestConditions uploadConditions = null;

            byte[] bytes       = null;
            string contentType = null;

            var mock = new Mock <BlobClient>();

            mock.Setup(c => c.UploadAsync(
                           It.IsAny <Stream>(),
                           It.IsAny <BlobHttpHeaders>(),
                           It.IsAny <IDictionary <string, string> >(),
                           It.IsAny <BlobRequestConditions>(),
                           It.IsAny <IProgress <long> >(),
                           It.IsAny <AccessTier?>(),
                           It.IsAny <StorageTransferOptions>(),
                           It.IsAny <CancellationToken>()))
            .Returns(async(Stream strm, BlobHttpHeaders headers, IDictionary <string, string> metaData, BlobRequestConditions conditions, IProgress <long> progress, AccessTier? access, StorageTransferOptions transfer, CancellationToken token) =>
            {
                using var memoryStream = new MemoryStream();
                strm.CopyTo(memoryStream);
                bytes            = memoryStream.ToArray();
                uploadConditions = conditions;
                contentType      = headers?.ContentType;

                await Task.Yield();

                var mockResponse    = new Mock <Response <BlobContentInfo> >();
                var blobContentInfo = BlobsModelFactory.BlobContentInfo(ETag.All, DateTimeOffset.Now.AddDays(-1), Array.Empty <byte>(), "", 1);

                mockResponse.Setup(c => c.Value).Returns(blobContentInfo);
                return(mockResponse.Object);
            });

            var repository = new AzureBlobXmlRepository(mock.Object);

            repository.StoreElement(new XElement("Element"), null);

            Assert.AreEqual("*", uploadConditions.IfNoneMatch.ToString());
            Assert.AreEqual("application/xml; charset=utf-8", contentType);
            var element = "<Element />";

            Assert.AreEqual(bytes, GetEnvelopedContent(element));
        }
コード例 #30
0
 protected override async Task <Stream> OpenWriteAsync(
     BlockBlobClient client,
     bool overwrite,
     int?bufferSize = null,
     BlobRequestConditions conditions     = null,
     Dictionary <string, string> metadata = null,
     Dictionary <string, string> tags     = null,
     HttpHeaderParameters httpHeaders     = null,
     IProgress <long> progressHandler     = null)
 => await client.OpenWriteAsync(overwrite, new BlockBlobOpenWriteOptions
 {
     BufferSize      = bufferSize,
     OpenConditions  = conditions,
     Metadata        = metadata,
     Tags            = tags,
     HttpHeaders     = httpHeaders.ToBlobHttpHeaders(),
     ProgressHandler = progressHandler
 });