sdk/storage/Azure.Storage.Blobs/src/PageBlobClient.cs (1,826 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Shared;
using Metadata = System.Collections.Generic.IDictionary<string, string>;
using Tags = System.Collections.Generic.IDictionary<string, string>;
#pragma warning disable SA1402 // File may only contain a single type
namespace Azure.Storage.Blobs.Specialized
{
/// <summary>
/// The <see cref="PageBlobClient"/> allows you to manipulate Azure
/// Storage page blobs.
///
/// Page blobs are a collection of 512-byte pages optimized for random
/// read and write operations. To create a page blob, you initialize the
/// page blob and specify the maximum size the page blob will grow. To add
/// or update the contents of a page blob, you write a page or pages by
/// specifying an offset and a range that align to 512-byte page
/// boundaries. A write to a page blob can overwrite just one page, some
/// pages, or up to 4 MB of the page blob. Writes to page blobs happen
/// in-place and are immediately committed to the blob. The maximum size
/// for a page blob is 8 TB.
/// </summary>
public class PageBlobClient : BlobBaseClient
{
/// <summary>
/// Gets the number of bytes in a page (512).
/// </summary>
public virtual int PageBlobPageBytes => 512;
/// <summary>
/// Gets the maximum number of bytes that can be sent in a call
/// to the <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
/// </summary>
public virtual int PageBlobMaxUploadPagesBytes => 4 * Constants.MB; // 4MB
/// <summary>
/// PageBlobRestClient.
/// </summary>
private readonly PageBlobRestClient _pageBlobRestClient;
/// <summary>
/// PageBlobRestClient.
/// </summary>
internal virtual PageBlobRestClient PageBlobRestClient => _pageBlobRestClient;
#region ctors
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class for mocking.
/// </summary>
protected PageBlobClient()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class.
/// </summary>
/// <param name="connectionString">
/// A connection string includes the authentication information
/// required for your application to access data in an Azure Storage
/// account at runtime.
///
/// For more information
/// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
/// Configure Azure Storage connection strings</see>
/// </param>
/// <param name="blobContainerName">
/// The name of the container containing this page blob.
/// </param>
/// <param name="blobName">
/// The name of this page blob.
/// </param>
public PageBlobClient(string connectionString, string blobContainerName, string blobName)
: base(connectionString, blobContainerName, blobName)
{
_pageBlobRestClient = BuildPageBlobRestClient(_uri);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class.
/// </summary>
/// <param name="connectionString">
/// A connection string includes the authentication information
/// required for your application to access data in an Azure Storage
/// account at runtime.
///
/// For more information,
/// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
/// Configure Azure Storage connection strings</see>
/// </param>
/// <param name="blobContainerName">
/// The name of the container containing this page blob.
/// </param>
/// <param name="blobName">
/// The name of this page blob.
/// </param>
/// <param name="options">
/// Optional client options that define the transport pipeline
/// policies for authentication, retries, etc., that are applied to
/// every request.
/// </param>
public PageBlobClient(string connectionString, string blobContainerName, string blobName, BlobClientOptions options)
: base(connectionString, blobContainerName, blobName, options)
{
_pageBlobRestClient = BuildPageBlobRestClient(_uri);
AssertNoClientSideEncryption(options);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class.
/// </summary>
/// <param name="blobUri">
/// A <see cref="Uri"/> referencing the page blob that includes the
/// name of the account, the name of the blob container, and the name of
/// the blob.
/// </param>
/// <param name="options">
/// Optional client options that define the transport pipeline
/// policies for authentication, retries, etc., that are applied to
/// every request.
/// </param>
public PageBlobClient(Uri blobUri, BlobClientOptions options = default)
: base(blobUri, options)
{
_pageBlobRestClient = BuildPageBlobRestClient(blobUri);
AssertNoClientSideEncryption(options);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class.
/// </summary>
/// <param name="blobUri">
/// A <see cref="Uri"/> referencing the page blob that includes the
/// name of the account, the name of the blob container, and the name of
/// the blob.
/// </param>
/// <param name="credential">
/// The shared key credential used to sign requests.
/// </param>
/// <param name="options">
/// Optional client options that define the transport pipeline
/// policies for authentication, retries, etc., that are applied to
/// every request.
/// </param>
public PageBlobClient(Uri blobUri, StorageSharedKeyCredential credential, BlobClientOptions options = default)
: base(blobUri, credential, options)
{
_pageBlobRestClient = BuildPageBlobRestClient(blobUri);
AssertNoClientSideEncryption(options);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class.
/// </summary>
/// <param name="blobUri">
/// A <see cref="Uri"/> referencing the page blob that includes the
/// name of the account, the name of the blob container, and the name of
/// the blob.
/// Must not contain shared access signature, which should be passed in the second parameter.
/// </param>
/// <param name="credential">
/// The shared access signature credential used to sign requests.
/// </param>
/// <param name="options">
/// Optional client options that define the transport pipeline
/// policies for authentication, retries, etc., that are applied to
/// every request.
/// </param>
/// <remarks>
/// This constructor should only be used when shared access signature needs to be updated during lifespan of this client.
/// </remarks>
public PageBlobClient(Uri blobUri, AzureSasCredential credential, BlobClientOptions options = default)
: base(blobUri, credential, options)
{
_pageBlobRestClient = BuildPageBlobRestClient(blobUri);
AssertNoClientSideEncryption(options);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class.
/// </summary>
/// <param name="blobUri">
/// A <see cref="Uri"/> referencing the page blob that includes the
/// name of the account, the name of the blob container, and the name of
/// the blob.
/// </param>
/// <param name="credential">
/// The token credential used to sign requests.
/// </param>
/// <param name="options">
/// Optional client options that define the transport pipeline
/// policies for authentication, retries, etc., that are applied to
/// every request.
/// </param>
public PageBlobClient(Uri blobUri, TokenCredential credential, BlobClientOptions options = default)
: base(blobUri, credential, options)
{
_pageBlobRestClient = BuildPageBlobRestClient(blobUri);
AssertNoClientSideEncryption(options);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class.
/// </summary>
/// <param name="blobUri">
/// A <see cref="Uri"/> referencing the page blob that includes the
/// name of the account, the name of the blob container, and the name of
/// the blob.
/// </param>
/// <param name="clientConfiguration">
/// <see cref="BlobClientConfiguration"/>.
/// </param>
internal PageBlobClient(
Uri blobUri,
BlobClientConfiguration clientConfiguration)
: base(
blobUri,
clientConfiguration,
clientSideEncryption: default)
{
_pageBlobRestClient = BuildPageBlobRestClient(blobUri);
}
private static void AssertNoClientSideEncryption(BlobClientOptions options)
{
if (options?._clientSideEncryptionOptions != default)
{
throw Errors.ClientSideEncryption.TypeNotSupported(typeof(PageBlobClient));
}
}
private PageBlobRestClient BuildPageBlobRestClient(Uri blobUri)
{
return new PageBlobRestClient(
clientDiagnostics: _clientConfiguration.ClientDiagnostics,
pipeline: _clientConfiguration.Pipeline,
url: blobUri.AbsoluteUri,
version: _clientConfiguration.Version.ToVersionString());
}
#endregion ctors
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class with an identical <see cref="Uri"/> source but the specified
/// snapshot timestamp.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </summary>
/// <param name="snapshot">The snapshot identifier.</param>
/// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
/// <remarks>
/// Pass null or empty string to remove the snapshot returning a URL
/// to the base blob.
/// </remarks>
public new PageBlobClient WithSnapshot(string snapshot) => (PageBlobClient)WithSnapshotCore(snapshot);
/// <summary>
/// Creates a new instance of the <see cref="PageBlobClient"/> class
/// with an identical <see cref="Uri"/> source but the specified
/// snapshot timestamp.
/// </summary>
/// <param name="snapshot">The snapshot identifier.</param>
/// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
protected sealed override BlobBaseClient WithSnapshotCore(string snapshot)
{
var builder = new BlobUriBuilder(Uri)
{
Snapshot = snapshot
};
return new PageBlobClient(
builder.ToUri(),
ClientConfiguration);
}
/// <summary>
/// Creates a new PageBlobClient object identical to the source but with the specified version ID.
/// Pass "" to remove the version ID returning a URL to the base blob.
/// </summary>
/// <param name="versionId">version ID</param>
/// <returns></returns>
public new PageBlobClient WithVersion(string versionId)
{
var builder = new BlobUriBuilder(Uri)
{
VersionId = versionId
};
return new PageBlobClient(
builder.ToUri(),
ClientConfiguration);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class with an identical <see cref="Uri"/> source but the specified
/// <paramref name="customerProvidedKey"/>.
///
/// </summary>
/// <param name="customerProvidedKey">The customer provided key.</param>
/// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
/// <remarks>
/// Pass null to remove the customer provide key in the returned <see cref="PageBlobClient"/>.
/// </remarks>
public new PageBlobClient WithCustomerProvidedKey(CustomerProvidedKey? customerProvidedKey)
{
BlobClientConfiguration newClientConfiguration = BlobClientConfiguration.DeepCopy(ClientConfiguration);
newClientConfiguration.CustomerProvidedKey = customerProvidedKey;
return new PageBlobClient(
blobUri: Uri,
clientConfiguration: newClientConfiguration);
}
/// <summary>
/// Initializes a new instance of the <see cref="PageBlobClient"/>
/// class with an identical <see cref="Uri"/> source but the specified
/// <paramref name="encryptionScope"/>.
///
/// </summary>
/// <param name="encryptionScope">The encryption scope.</param>
/// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
/// <remarks>
/// Pass null to remove the encryption scope in the returned <see cref="PageBlobClient"/>.
/// </remarks>
public new PageBlobClient WithEncryptionScope(string encryptionScope)
{
BlobClientConfiguration newClientConfiguration = BlobClientConfiguration.DeepCopy(ClientConfiguration);
newClientConfiguration.EncryptionScope = encryptionScope;
return new PageBlobClient(
blobUri: Uri,
clientConfiguration: newClientConfiguration);
}
#region Create
/// <summary>
/// The <see cref="Create(long, PageBlobCreateOptions, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>.
/// The content of any existing blob is overwritten with the newly initialized page blob
/// To add content to the page blob, call the
/// <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </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
/// newly created page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<BlobContentInfo> Create(
long size,
PageBlobCreateOptions options,
CancellationToken cancellationToken = default) =>
CreateInternal(
size,
options?.SequenceNumber,
options?.HttpHeaders,
options?.Metadata,
options?.Tags,
options?.Conditions,
options?.ImmutabilityPolicy,
options?.LegalHold,
options?.PremiumPageBlobAccessTier,
async: false,
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="CreateAsync(long, PageBlobCreateOptions, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>.
/// The content of any existing blob is overwritten with the newly initialized page blob
/// To add content to the page blob, call the
/// <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </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
/// newly created page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<BlobContentInfo>> CreateAsync(
long size,
PageBlobCreateOptions options,
CancellationToken cancellationToken = default) =>
await CreateInternal(
size,
options?.SequenceNumber,
options?.HttpHeaders,
options?.Metadata,
options?.Tags,
options?.Conditions,
options?.ImmutabilityPolicy,
options?.LegalHold,
options?.PremiumPageBlobAccessTier,
async: true,
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="Create(long, long?, BlobHttpHeaders, Metadata, PageBlobRequestConditions, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>. The content of any
/// existing blob is overwritten with the newly initialized page blob
/// To add content to the page blob, call the
/// <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="sequenceNumber">
/// Optional user-controlled value that you can use to track requests.
/// The value of the <paramref name="sequenceNumber"/> must be between
/// 0 and 2^63 - 1. The default value is 0.
/// </param>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new page blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this page blob.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the creation of this new page blob.
/// </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
/// newly created page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual Response<BlobContentInfo> Create(
long size,
long? sequenceNumber = default,
BlobHttpHeaders httpHeaders = default,
Metadata metadata = default,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
CreateInternal(
size: size,
sequenceNumber: sequenceNumber,
httpHeaders: httpHeaders,
metadata: metadata,
tags: default,
conditions: conditions,
immutabilityPolicy: default,
legalHold: default,
premiumPageBlobAccessTier: default,
async: false,
cancellationToken: cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="CreateAsync(long, long?, BlobHttpHeaders, Metadata, PageBlobRequestConditions, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>. The content of any
/// existing blob is overwritten with the newly initialized page blob
/// To add content to the page blob, call the
/// <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="sequenceNumber">
/// Optional user-controlled value that you can use to track requests.
/// The value of the <paramref name="sequenceNumber"/> must be between
/// 0 and 2^63 - 1. The default value is 0.
/// </param>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new page blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this page blob.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the creation of this new page blob.
/// </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
/// newly created page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual async Task<Response<BlobContentInfo>> CreateAsync(
long size,
long? sequenceNumber = default,
BlobHttpHeaders httpHeaders = default,
Metadata metadata = default,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
await CreateInternal(
size: size,
sequenceNumber: sequenceNumber,
httpHeaders: httpHeaders,
metadata: metadata,
tags: default,
conditions: conditions,
immutabilityPolicy: default,
legalHold: default,
premiumPageBlobAccessTier: default,
async: true,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="CreateIfNotExists(long, PageBlobCreateOptions, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>. If the blob already
/// exists, the content of the existing blob will remain unchanged. If the blob does not already exists,
/// a new page blob with the specified <paramref name="size"/> will be created.
/// <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </param>
/// /// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
/// describing the newly created page blob. Otherwise, <c>null</c>.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<BlobContentInfo> CreateIfNotExists(
long size,
PageBlobCreateOptions options,
CancellationToken cancellationToken = default) =>
CreateIfNotExistsInternal(
size,
options?.SequenceNumber,
options?.HttpHeaders,
options?.Metadata,
options?.Tags,
options?.ImmutabilityPolicy,
options?.LegalHold,
options?.PremiumPageBlobAccessTier,
async: false,
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="CreateIfNotExistsAsync(long, PageBlobCreateOptions, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>. If the blob already
/// exists, the content of the existing blob will remain unchanged. If the blob does not already exists,
/// a new page blob with the specified <paramref name="size"/> will be created.
/// <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </param>
/// /// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
/// describing the newly created page blob. Otherwise, <c>null</c>.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<BlobContentInfo>> CreateIfNotExistsAsync(
long size,
PageBlobCreateOptions options,
CancellationToken cancellationToken = default) =>
await CreateIfNotExistsInternal(
size,
options?.SequenceNumber,
options?.HttpHeaders,
options?.Metadata,
options?.Tags,
options?.ImmutabilityPolicy,
options?.LegalHold,
options?.PremiumPageBlobAccessTier,
async: true,
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="CreateIfNotExists(long, long?, BlobHttpHeaders, Metadata, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>. If the blob already
/// exists, the content of the existing blob will remain unchanged. If the blob does not already exists,
/// a new page blob with the specified <paramref name="size"/> will be created.
/// <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="sequenceNumber">
/// Optional user-controlled value that you can use to track requests.
/// The value of the <paramref name="sequenceNumber"/> must be between
/// 0 and 2^63 - 1. The default value is 0.
/// </param>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new page blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this page blob.
/// </param>
/// /// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
/// describing the newly created page blob. Otherwise, <c>null</c>.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual Response<BlobContentInfo> CreateIfNotExists(
long size,
long? sequenceNumber = default,
BlobHttpHeaders httpHeaders = default,
Metadata metadata = default,
CancellationToken cancellationToken = default) =>
CreateIfNotExistsInternal(
size: size,
sequenceNumber: sequenceNumber,
httpHeaders: httpHeaders,
metadata: metadata,
tags: default,
immutabilityPolicy: default,
legalHold: default,
premiumPageBlobAccessTier: default,
async: false,
cancellationToken: cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="CreateIfNotExistsAsync(long, long?, BlobHttpHeaders, Metadata, CancellationToken)"/>
/// operation creates a new page blob of the specified <paramref name="size"/>. If the blob already exists,
/// the content of the existing blob will remain unchanged. If the blob does not already exists,
/// a new page blob with the specified <paramref name="size"/> will be created.
/// <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="sequenceNumber">
/// Optional user-controlled value that you can use to track requests.
/// The value of the <paramref name="sequenceNumber"/> must be between
/// 0 and 2^63 - 1. The default value is 0.
/// </param>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new page blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
/// describing the newly created page blob. Otherwise, <c>null</c>.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual async Task<Response<BlobContentInfo>> CreateIfNotExistsAsync(
long size,
long? sequenceNumber = default,
BlobHttpHeaders httpHeaders = default,
Metadata metadata = default,
CancellationToken cancellationToken = default) =>
await CreateIfNotExistsInternal(
size: size,
sequenceNumber: sequenceNumber,
httpHeaders: httpHeaders,
metadata: metadata,
tags: default,
immutabilityPolicy: default,
legalHold: default,
premiumPageBlobAccessTier: default,
async: true,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="CreateIfNotExistsInternal"/> operation creates a new page blob
/// of the specified <paramref name="size"/>. If the blob already exists, the content of
/// the existing blob will remain unchanged. If the blob does not already exists,
/// a new page blob with the specified <paramref name="size"/> will be created.
/// To add content to the page blob, call the
/// <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="sequenceNumber">
/// Optional user-controlled value that you can use to track requests.
/// The value of the <paramref name="sequenceNumber"/> must be between
/// 0 and 2^63 - 1. The default value is 0.
/// </param>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new page blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this page blob.
/// </param>
/// <param name="tags">
/// Optional tags to set for this page blob.
/// </param>
/// <param name="immutabilityPolicy">
/// Optional <see cref="BlobImmutabilityPolicy"/> to set on the blob.
/// Note that is parameter is only applicable to a blob within a container that
/// has immutable storage with versioning enabled.
/// </param>
/// <param name="legalHold">
/// Optional. Indicates if a legal hold should be placed on the blob.
/// Note that is parameter is only applicable to a blob within a container that
/// has immutable storage with versioning enabled.
/// </param>
/// <param name="premiumPageBlobAccessTier">
/// Optional. Sets the page blob tiers on the blob.
/// This is only supported for page blobs on premium accounts.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
/// describing the newly created page blob. Otherwise, <c>null</c>.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<BlobContentInfo>> CreateIfNotExistsInternal(
long size,
long? sequenceNumber,
BlobHttpHeaders httpHeaders,
Metadata metadata,
Tags tags,
BlobImmutabilityPolicy immutabilityPolicy,
bool? legalHold,
PremiumPageBlobAccessTier? premiumPageBlobAccessTier,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(size)}: {size}\n" +
$"{nameof(sequenceNumber)}: {sequenceNumber}\n" +
$"{nameof(httpHeaders)}: {httpHeaders}");
PageBlobRequestConditions conditions = new PageBlobRequestConditions { IfNoneMatch = new ETag(Constants.Wildcard) };
try
{
return await CreateInternal(
size,
sequenceNumber,
httpHeaders,
metadata,
tags,
conditions,
immutabilityPolicy,
legalHold,
premiumPageBlobAccessTier,
async,
cancellationToken,
$"{nameof(PageBlobClient)}.{nameof(CreateIfNotExists)}")
.ConfigureAwait(false);
}
catch (RequestFailedException storageRequestFailedException)
when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobAlreadyExists)
{
return default;
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
}
}
}
/// <summary>
/// The <see cref="CreateInternal"/> operation creates a new page blob
/// of the specified <paramref name="size"/>. The content of any
/// existing blob is overwritten with the newly initialized page blob
/// To add content to the page blob, call the
/// <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation.
///
/// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary.
/// </param>
/// <param name="sequenceNumber">
/// Optional user-controlled value that you can use to track requests.
/// The value of the <paramref name="sequenceNumber"/> must be between
/// 0 and 2^63 - 1. The default value is 0.
/// </param>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new page blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this page blob.
/// </param>
/// <param name="tags">
/// Optional tags to set for this page blob.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the creation of this new page blob.
/// </param>
/// <param name="immutabilityPolicy">
/// Optional <see cref="BlobImmutabilityPolicy"/> to set on the blob.
/// Note that is parameter is only applicable to a blob within a container that
/// has immutable storage with versioning enabled.
/// </param>
/// <param name="legalHold">
/// Optional. Indicates if a legal hold should be placed on the blob.
/// Note that is parameter is only applicable to a blob within a container that
/// has immutable storage with versioning enabled.
/// </param>
/// <param name="premiumPageBlobAccessTier">
/// Optional. Sets the page blob tiers on the blob.
/// This is only supported for page blobs on premium accounts.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <param name="operationName">
/// Optional. To indicate if the name of the operation.
/// </param>
/// <returns>
/// A <see cref="Response{BlobContentInfo}"/> describing the
/// newly created page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<BlobContentInfo>> CreateInternal(
long size,
long? sequenceNumber,
BlobHttpHeaders httpHeaders,
Metadata metadata,
Tags tags,
PageBlobRequestConditions conditions,
BlobImmutabilityPolicy immutabilityPolicy,
bool? legalHold,
PremiumPageBlobAccessTier? premiumPageBlobAccessTier,
bool async,
CancellationToken cancellationToken,
string operationName = null)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(size)}: {size}\n" +
$"{nameof(sequenceNumber)}: {sequenceNumber}\n" +
$"{nameof(httpHeaders)}: {httpHeaders}");
operationName ??= $"{nameof(PageBlobClient)}.{nameof(Create)}";
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope(operationName);
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.Create),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageBlobCreateHeaders> response;
if (async)
{
response = await PageBlobRestClient.CreateAsync(
contentLength: 0,
blobContentLength: size,
tier: premiumPageBlobAccessTier,
blobContentType: httpHeaders?.ContentType,
blobContentEncoding: httpHeaders?.ContentEncoding,
blobContentLanguage: httpHeaders?.ContentLanguage,
blobContentMD5: httpHeaders?.ContentHash,
blobCacheControl: httpHeaders?.CacheControl,
metadata: metadata,
leaseId: conditions?.LeaseId,
blobContentDisposition: httpHeaders?.ContentDisposition,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
encryptionScope: ClientConfiguration.EncryptionScope,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
blobSequenceNumber: sequenceNumber,
blobTagsString: tags?.ToTagsString(),
immutabilityPolicyExpiry: immutabilityPolicy?.ExpiresOn,
immutabilityPolicyMode: immutabilityPolicy?.PolicyMode,
legalHold: legalHold,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.Create(
contentLength: 0,
blobContentLength: size,
tier: premiumPageBlobAccessTier,
blobContentType: httpHeaders?.ContentType,
blobContentEncoding: httpHeaders?.ContentEncoding,
blobContentLanguage: httpHeaders?.ContentLanguage,
blobContentMD5: httpHeaders?.ContentHash,
blobCacheControl: httpHeaders?.CacheControl,
metadata: metadata,
leaseId: conditions?.LeaseId,
blobContentDisposition: httpHeaders?.ContentDisposition,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
encryptionScope: ClientConfiguration.EncryptionScope,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
blobSequenceNumber: sequenceNumber,
blobTagsString: tags?.ToTagsString(),
immutabilityPolicyExpiry: immutabilityPolicy?.ExpiresOn,
immutabilityPolicyMode: immutabilityPolicy?.PolicyMode,
legalHold: legalHold,
cancellationToken: cancellationToken);
}
return Response.FromValue(
response.ToBlobContentInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion Create
#region UploadPages
/// <summary>
/// The <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation writes
/// <paramref name="content"/> to a range of pages in a page blob,
/// starting at <paramref name="offset"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="content">
/// A <see cref="Stream"/> containing the content of the pages to
/// upload. The content can be up to 4 MB in size.
/// </param>
/// <param name="offset">
/// Specifies the starting offset for the <paramref name="content"/>
/// to be written as a page. Given that pages must be aligned with
/// 512-byte boundaries, the start offset must be a modulus of 512.
/// </param>
/// <param name="transactionalContentHash">
/// Optional MD5 hash of the block content. This hash is used to
/// verify the integrity of the block during transport. When this hash
/// is specified, the storage service compares the hash of the content
/// that has arrived with this value. Note that this MD5 hash is not
/// stored with the blob. If the two hashes do not match, the
/// operation will fail with a <see cref="RequestFailedException"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on uploading pages to this page blob.
/// </param>
/// <param name="progressHandler">
/// Optional <see cref="IProgress{Long}"/> to provide
/// progress updates about data transfers.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
#pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
public virtual Response<PageInfo> UploadPages(
#pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
Stream content,
long offset,
byte[] transactionalContentHash,
PageBlobRequestConditions conditions,
IProgress<long> progressHandler,
CancellationToken cancellationToken)
{
return UploadPagesInternal(
content,
offset,
transactionalContentHash.ToValidationOptions(),
conditions,
progressHandler,
false, // async
cancellationToken)
.EnsureCompleted();
}
/// <summary>
/// The <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> operation writes
/// <paramref name="content"/> to a range of pages in a page blob,
/// starting at <paramref name="offset"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="content">
/// A <see cref="Stream"/> containing the content of the pages to
/// upload. The content can be up to 4 MB in size.
/// </param>
/// <param name="offset">
/// Specifies the starting offset for the <paramref name="content"/>
/// to be written as a page. Given that pages must be aligned with
/// 512-byte boundaries, the start offset must be a modulus of 512.
/// </param>
/// <param name="transactionalContentHash">
/// Optional MD5 hash of the block content. This hash is used to
/// verify the integrity of the block during transport. When this hash
/// is specified, the storage service compares the hash of the content
/// that has arrived with this value. Note that this MD5 hash is not
/// stored with the blob. If the two hashes do not match, the
/// operation will fail with a <see cref="RequestFailedException"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on uploading pages to this page blob.
/// </param>
/// <param name="progressHandler">
/// Optional <see cref="IProgress{Long}"/> to provide
/// progress updates about data transfers.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
#pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
public virtual async Task<Response<PageInfo>> UploadPagesAsync(
#pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
Stream content,
long offset,
byte[] transactionalContentHash,
PageBlobRequestConditions conditions,
IProgress<long> progressHandler,
CancellationToken cancellationToken)
{
return await UploadPagesInternal(
content,
offset,
transactionalContentHash.ToValidationOptions(),
conditions,
progressHandler,
true, // async
cancellationToken)
.ConfigureAwait(false);
}
/// <summary>
/// The <see cref="UploadPages(Stream, long, PageBlobUploadPagesOptions, CancellationToken)"/> operation writes
/// <paramref name="content"/> to a range of pages in a page blob,
/// starting at <paramref name="offset"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="content">
/// A <see cref="Stream"/> containing the content of the pages to
/// upload. The content can be up to 4 MB in size.
/// </param>
/// <param name="offset">
/// Specifies the starting offset for the <paramref name="content"/>
/// to be written as a page. Given that pages must be aligned with
/// 512-byte boundaries, the start offset must be a modulus of 512.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<PageInfo> UploadPages(
Stream content,
long offset,
PageBlobUploadPagesOptions options = default,
CancellationToken cancellationToken = default) =>
UploadPagesInternal(
content,
offset,
options?.TransferValidation,
options?.Conditions,
options?.ProgressHandler,
false, // async
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="UploadPagesAsync(Stream, long, PageBlobUploadPagesOptions, CancellationToken)"/> operation writes
/// <paramref name="content"/> to a range of pages in a page blob,
/// starting at <paramref name="offset"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="content">
/// A <see cref="Stream"/> containing the content of the pages to
/// upload. The content can be up to 4 MB in size.
/// </param>
/// <param name="offset">
/// Specifies the starting offset for the <paramref name="content"/>
/// to be written as a page. Given that pages must be aligned with
/// 512-byte boundaries, the start offset must be a modulus of 512.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<PageInfo>> UploadPagesAsync(
Stream content,
long offset,
PageBlobUploadPagesOptions options = default,
CancellationToken cancellationToken = default) =>
await UploadPagesInternal(
content,
offset,
options?.TransferValidation,
options?.Conditions,
options?.ProgressHandler,
true, // async
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="UploadPagesInternal"/> operation writes
/// <paramref name="content"/> to a range of pages in a page blob,
/// starting at <paramref name="offset"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="content">
/// A <see cref="Stream"/> containing the content of the pages to
/// upload. The content can be up to 4 MB in size.
/// </param>
/// <param name="offset">
/// Specifies the starting offset for the <paramref name="content"/>
/// to be written as a page. Given that pages must be aligned with
/// 512-byte boundaries, the start offset must be a modulus of 512.
/// </param>
/// <param name="transferValidationOverride">
/// Optional transfer validation options for uploading the page range.
/// </param>
/// <param name="conditions">
/// Request conditions for page upload.
/// </param>
/// <param name="progressHandler">
/// Progress handler for upload operation.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
internal async Task<Response<PageInfo>> UploadPagesInternal(
Stream content,
long offset,
UploadTransferValidationOptions transferValidationOverride,
PageBlobRequestConditions conditions,
IProgress<long> progressHandler,
bool async,
CancellationToken cancellationToken)
{
UploadTransferValidationOptions validationOptions = transferValidationOverride ?? ClientConfiguration.TransferValidation.Upload;
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(offset)}: {offset}\n" +
$"{nameof(conditions)}: {conditions}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(UploadPages)}");
// All PageBlobRequestConditions are valid.
conditions.ValidateConditionsNotPresent(
invalidConditions: BlobRequestConditionProperty.None,
operationName: nameof(PageBlobClient.UploadPages),
parameterName: nameof(conditions));
try
{
scope.Start();
Errors.VerifyStreamPosition(content, nameof(content));
// compute hash BEFORE attaching progress handler
ContentHasher.GetHashResult hashResult = await ContentHasher.GetHashOrDefaultInternal(
content,
validationOptions,
async,
cancellationToken).ConfigureAwait(false);
content = content?.WithNoDispose().WithProgress(progressHandler);
HttpRange range = new HttpRange(offset, (content?.Length - content?.Position) ?? null);
ResponseWithHeaders<PageBlobUploadPagesHeaders> response;
if (async)
{
response = await PageBlobRestClient.UploadPagesAsync(
contentLength: (content?.Length - content?.Position) ?? 0,
body: content,
transactionalContentCrc64: hashResult?.StorageCrc64AsArray,
transactionalContentMD5: hashResult?.MD5AsArray,
range: range.ToString(),
leaseId: conditions?.LeaseId,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
encryptionScope: ClientConfiguration.EncryptionScope,
ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.UploadPages(
contentLength: (content?.Length - content?.Position) ?? 0,
body: content,
transactionalContentCrc64: hashResult?.StorageCrc64AsArray,
transactionalContentMD5: hashResult?.MD5AsArray,
range: range.ToString(),
leaseId: conditions?.LeaseId,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
encryptionScope: ClientConfiguration.EncryptionScope,
ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken);
}
return Response.FromValue(
response.ToPageInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion UploadPages
#region ClearPages
/// <summary>
/// The <see cref="ClearPages"/> operation clears one or more
/// pages from the page blob, as specificed by the <paramref name="range"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="range">
/// Specifies the range of bytes to be cleared. Both the start and
/// end of the range must be specified. For a page clear operation,
/// the page range can be up to the value of the blob's full size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on clearing pages from this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<PageInfo> ClearPages(
HttpRange range,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
ClearPagesInternal(
range,
conditions,
false, // async
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="ClearPagesAsync"/> operation clears one or more
/// pages from the page blob, as specificed by the <paramref name="range"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="range">
/// Specifies the range of bytes to be cleared. Both the start and
/// end of the range must be specified. For a page clear operation,
/// the page range can be up to the value of the blob's full size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on clearing pages from this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<PageInfo>> ClearPagesAsync(
HttpRange range,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
await ClearPagesInternal(
range,
conditions,
true, // async
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="ClearPagesInternal"/> operation clears one or more
/// pages from the page blob, as specificed by the <paramref name="range"/>.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
/// Put Page</see>.
/// </summary>
/// <param name="range">
/// Specifies the range of bytes to be cleared. Both the start and
/// end of the range must be specified. For a page clear operation,
/// the page range can be up to the value of the blob's full size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on clearing pages from this page blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<PageInfo>> ClearPagesInternal(
HttpRange range,
PageBlobRequestConditions conditions,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(conditions)}: {conditions}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(ClearPages)}");
// All PageBlobRequestConditions are valid.
conditions.ValidateConditionsNotPresent(
invalidConditions: BlobRequestConditionProperty.None,
operationName: nameof(PageBlobClient.ClearPages),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageBlobClearPagesHeaders> response;
if (async)
{
response = await PageBlobRestClient.ClearPagesAsync(
contentLength: 0,
range: range.ToString(),
leaseId: conditions?.LeaseId,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionScope: ClientConfiguration.EncryptionScope,
ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.ClearPages(
contentLength: 0,
range: range.ToString(),
leaseId: conditions?.LeaseId,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionScope: ClientConfiguration.EncryptionScope,
ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken);
}
return Response.FromValue(
response.ToPageInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion ClearPages
#region GetPageRanges
/// <summary>
/// The <see cref="GetAllPageRanges(GetPageRangesOptions, CancellationToken)"/> operation returns the list of
/// valid page ranges for a page blob or snapshot of a page blob.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Page{PageBlobRange}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Pageable<PageRangeItem> GetAllPageRanges(
GetPageRangesOptions options = default,
CancellationToken cancellationToken = default)
=> new GetPageRangesAsyncCollection(
diff: false,
client: this,
range: options?.Range,
snapshot: options?.Snapshot,
previousSnapshot: null,
previousSnapshotUri: null,
requestConditions: options?.Conditions,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetAllPageRanges)}")
.ToSyncCollection(cancellationToken);
/// <summary>
/// The <see cref="GetAllPageRangesAsync(GetPageRangesOptions, CancellationToken)"/> operation returns the list of
/// valid page ranges for a page blob or snapshot of a page blob.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="AsyncPageable{PageBlobRange}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual AsyncPageable<PageRangeItem> GetAllPageRangesAsync(
GetPageRangesOptions options = default,
CancellationToken cancellationToken = default)
=> new GetPageRangesAsyncCollection(
diff: false,
client: this,
range: options?.Range,
snapshot: options?.Snapshot,
previousSnapshot: null,
previousSnapshotUri: null,
requestConditions: options?.Conditions,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetAllPageRanges)}")
.ToAsyncCollection(cancellationToken);
/// <summary>
/// The <see cref="GetAllPageRangesInteral"/> operation returns the list
/// of valid page ranges for a page blob or snapshot of a page blob.
///
/// For more information, see For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="marker">
/// An optional string value that identifies the segment of the list
/// of blobs to be returned with the next listing operation. The
/// operation returns a non-empty <see cref="ListBlobsFlatSegmentResponse.NextMarker"/>
/// if the listing operation did not return all blobs remaining to be
/// listed with the current segment. The NextMarker value can
/// be used as the value for the <paramref name="marker"/> parameter
/// in a subsequent call to request the next segment of list items.
/// </param>
/// <param name="pageSizeHint">
/// Gets or sets a value indicating the size of the page that should be
/// requested.
/// </param>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
internal async Task<ResponseWithHeaders<PageList, PageBlobGetPageRangesHeaders>> GetAllPageRangesInteral(
string marker,
int? pageSizeHint,
HttpRange? range,
string snapshot,
PageBlobRequestConditions conditions,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(marker)}: {marker}\n" +
$"{nameof(pageSizeHint)}: {pageSizeHint}\n" +
$"{nameof(range)}: {range}\n" +
$"{nameof(snapshot)}: {snapshot}\n" +
$"{nameof(conditions)}: {conditions}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(GetAllPageRanges)}");
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.GetPageRanges),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageList, PageBlobGetPageRangesHeaders> response;
if (async)
{
response = await PageBlobRestClient.GetPageRangesAsync(
snapshot: snapshot,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
marker: marker,
maxresults: pageSizeHint,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.GetPageRanges(
snapshot: snapshot,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
marker: marker,
maxresults: pageSizeHint,
cancellationToken: cancellationToken);
}
// Return an exploding Response on 304
if (response.IsUnavailable())
{
return response.GetRawResponse().AsNoBodyResponse<ResponseWithHeaders<PageList, PageBlobGetPageRangesHeaders>>();
}
return response;
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
/// <summary>
/// The <see cref="GetPageRanges(HttpRange?, string, PageBlobRequestConditions, CancellationToken)"/>
/// operation returns the list of valid page ranges for a page blob or snapshot of a page blob.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual Response<PageRangesInfo> GetPageRanges(
HttpRange? range = null,
string snapshot = null,
PageBlobRequestConditions conditions = null,
CancellationToken cancellationToken = default) =>
GetPageRangesInternal(
range,
snapshot,
conditions,
false, // async
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="GetPageRangesAsync(HttpRange?, string, PageBlobRequestConditions, CancellationToken)"/>
/// operation returns the list of valid page ranges for a page blob or snapshot of a page blob.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual async Task<Response<PageRangesInfo>> GetPageRangesAsync(
HttpRange? range = null,
string snapshot = null,
PageBlobRequestConditions conditions = null,
CancellationToken cancellationToken = default) =>
await GetPageRangesInternal(
range,
snapshot,
conditions,
true, // async
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="GetPageRangesInternal"/> operation returns the list
/// of valid page ranges for a page blob or snapshot of a page blob.
///
/// For more information, see For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<PageRangesInfo>> GetPageRangesInternal(
HttpRange? range,
string snapshot,
PageBlobRequestConditions conditions,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(snapshot)}: {snapshot}\n" +
$"{nameof(conditions)}: {conditions}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(GetPageRanges)}");
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.GetPageRanges),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageList, PageBlobGetPageRangesHeaders> response;
if (async)
{
response = await PageBlobRestClient.GetPageRangesAsync(
snapshot: snapshot,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.GetPageRanges(
snapshot: snapshot,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken);
}
// Return an exploding Response on 304
return response.IsUnavailable()
? response.GetRawResponse().AsNoBodyResponse<PageRangesInfo>()
: Response.FromValue(
response.ToPageRangesInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion GetPageRanges
#region GetPageRangesDiff
/// <summary>
/// The <see cref="GetAllPageRangesDiff(GetPageRangesDiffOptions, CancellationToken)"/>
/// operation returns the list of page ranges that differ between a
/// <see cref="GetPageRangesDiffOptions.PreviousSnapshot"/> and this page blob. Changed pages
/// include both updated and cleared pages.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Pageable{PageBlobRange}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Pageable<PageRangeItem> GetAllPageRangesDiff(
GetPageRangesDiffOptions options = default,
CancellationToken cancellationToken = default)
=> new GetPageRangesAsyncCollection(
diff: true,
client: this,
range: options?.Range,
snapshot: options?.Snapshot,
previousSnapshot: options?.PreviousSnapshot,
previousSnapshotUri: null,
requestConditions: options?.Conditions,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetAllPageRangesDiff)}")
.ToSyncCollection(cancellationToken);
/// <summary>
/// The <see cref="GetAllPageRangesDiffAsync(GetPageRangesDiffOptions, CancellationToken)"/>
/// operation returns the list of page ranges that differ between a
/// <see cref="GetPageRangesDiffOptions.PreviousSnapshot"/> and this page blob. Changed pages
/// include both updated and cleared pages.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="AsyncPageable{PageBlobRange}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual AsyncPageable<PageRangeItem> GetAllPageRangesDiffAsync(
GetPageRangesDiffOptions options = default,
CancellationToken cancellationToken = default)
=> new GetPageRangesAsyncCollection(
diff: true,
client: this,
range: options?.Range,
snapshot: options?.Snapshot,
previousSnapshot: options?.PreviousSnapshot,
previousSnapshotUri: null,
requestConditions: options?.Conditions,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetAllPageRangesDiff)}")
.ToAsyncCollection(cancellationToken);
/// <summary>
/// The <see cref="GetAllPageRangesDiffInternal"/> operation returns the
/// list of page ranges that differ between a
/// <paramref name="previousSnapshot"/> and this page blob. Changed pages
/// include both updated and cleared pages.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="marker">
/// An optional string value that identifies the segment of the list
/// of blobs to be returned with the next listing operation. The
/// operation returns a non-empty <see cref="ListBlobsFlatSegmentResponse.NextMarker"/>
/// if the listing operation did not return all blobs remaining to be
/// listed with the current segment. The NextMarker value can
/// be used as the value for the <paramref name="marker"/> parameter
/// in a subsequent call to request the next segment of list items.
/// </param>
/// <param name="pageSizeHint">
/// Gets or sets a value indicating the size of the page that should be
/// requested.
/// </param>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="previousSnapshot">
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshot"/> is the older of the two.
/// </param>
/// <param name="previousSnapshotUri">
/// This parameter only works with managed disk storage accounts.
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshotUri"/> is the older of the two.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="operationName">
/// The name of the operation.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="ResponseWithHeaders{PageList, PageBlobGetPageRangesDiffHeaders}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
internal async Task<ResponseWithHeaders<PageList, PageBlobGetPageRangesDiffHeaders>> GetAllPageRangesDiffInternal(
string marker,
int? pageSizeHint,
HttpRange? range,
string snapshot,
string previousSnapshot,
Uri previousSnapshotUri,
PageBlobRequestConditions conditions,
bool async,
string operationName,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(marker)}: {marker}\n" +
$"{nameof(pageSizeHint)}: {pageSizeHint}\n" +
$"{nameof(range)}: {range}\n" +
$"{nameof(snapshot)}: {snapshot}\n" +
$"{nameof(previousSnapshot)}: {previousSnapshot}\n" +
$"{nameof(previousSnapshotUri)}: {previousSnapshotUri}\n" +
$"{nameof(conditions)}: {conditions}");
operationName ??= $"{nameof(PageBlobClient)}.{nameof(GetAllPageRangesDiff)}";
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope(operationName);
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.GetPageRanges),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageList, PageBlobGetPageRangesDiffHeaders> response;
if (async)
{
response = await PageBlobRestClient.GetPageRangesDiffAsync(
snapshot: snapshot,
prevsnapshot: previousSnapshot,
prevSnapshotUrl: previousSnapshotUri?.AbsoluteUri,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
marker: marker,
maxresults: pageSizeHint,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.GetPageRangesDiff(
snapshot: snapshot,
prevsnapshot: previousSnapshot,
prevSnapshotUrl: previousSnapshotUri?.AbsoluteUri,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
marker: marker,
maxresults: pageSizeHint,
cancellationToken: cancellationToken);
}
// Return an exploding Response on 304
if (response.IsUnavailable())
{
return response.GetRawResponse().AsNoBodyResponse<ResponseWithHeaders<PageList, PageBlobGetPageRangesDiffHeaders>>();
}
return response;
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
/// <summary>
/// The <see cref="GetPageRangesDiff(HttpRange?, string, string, PageBlobRequestConditions, CancellationToken)"/>
/// operation returns the list of page ranges that differ between a
/// <paramref name="previousSnapshot"/> and this page blob. Changed pages
/// include both updated and cleared pages.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="previousSnapshot">
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshot"/> is the older of the two.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual Response<PageRangesInfo> GetPageRangesDiff(
HttpRange? range = null,
string snapshot = null,
string previousSnapshot = null,
PageBlobRequestConditions conditions = null,
CancellationToken cancellationToken = default) =>
GetPageRangesDiffInternal(
range,
snapshot,
previousSnapshot,
previousSnapshotUri: default,
conditions,
async: false,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetPageRangesDiff)}",
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="GetPageRangesDiffAsync(HttpRange?, string, string, PageBlobRequestConditions, CancellationToken)"/>
/// operation returns the list of page ranges that differ between a
/// <paramref name="previousSnapshot"/> and this page blob. Changed pages
/// include both updated and cleared pages.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="previousSnapshot">
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshot"/> is the older of the two.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual async Task<Response<PageRangesInfo>> GetPageRangesDiffAsync(
HttpRange? range = null,
string snapshot = null,
string previousSnapshot = null,
PageBlobRequestConditions conditions = null,
CancellationToken cancellationToken = default) =>
await GetPageRangesDiffInternal(
range,
snapshot,
previousSnapshot,
previousSnapshotUri: default,
conditions,
async: true,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetPageRangesDiff)}",
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="GetPageRangesDiffInternal"/> operation returns the
/// list of page ranges that differ between a
/// <paramref name="previousSnapshot"/> and this page blob. Changed pages
/// include both updated and cleared pages.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="previousSnapshot">
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshot"/> is the older of the two.
/// </param>
/// <param name="previousSnapshotUri">
/// This parameter only works with managed disk storage accounts.
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshotUri"/> is the older of the two.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="operationName">
/// The name of the operation.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<PageRangesInfo>> GetPageRangesDiffInternal(
HttpRange? range,
string snapshot,
string previousSnapshot,
Uri previousSnapshotUri,
PageBlobRequestConditions conditions,
bool async,
string operationName,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(snapshot)}: {snapshot}\n" +
$"{nameof(previousSnapshot)}: {previousSnapshot}\n" +
$"{nameof(previousSnapshotUri)}: {previousSnapshotUri}\n" +
$"{nameof(conditions)}: {conditions}");
operationName ??= $"{nameof(PageBlobClient)}.{nameof(GetPageRangesDiff)}";
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope(operationName);
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.GetPageRangesDiff),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageList, PageBlobGetPageRangesDiffHeaders> response;
if (async)
{
response = await PageBlobRestClient.GetPageRangesDiffAsync(
snapshot: snapshot,
prevsnapshot: previousSnapshot,
prevSnapshotUrl: previousSnapshotUri?.AbsoluteUri,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.GetPageRangesDiff(
snapshot: snapshot,
prevsnapshot: previousSnapshot,
prevSnapshotUrl: previousSnapshotUri?.AbsoluteUri,
range: range?.ToString(),
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken);
}
// Return an exploding Response on 304
return response.IsUnavailable() ?
response.GetRawResponse().AsNoBodyResponse<PageRangesInfo>() :
Response.FromValue(
response.ToPageRangesInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion GetPageRangesDiff
#region GetManagedDiskPageRangesDiff
/// <summary>
/// The <see cref="GetManagedDiskPageRangesDiff"/>
/// operation returns the list of page ranges that differ between a
/// <paramref name="previousSnapshotUri"/> and this page blob. Changed pages
/// include both updated and cleared pages. This API only works with
/// managed disk storage accounts.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="previousSnapshotUri">
/// This parameter only works with managed disk storage accounts.
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshotUri"/> is the older of the two.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<PageRangesInfo> GetManagedDiskPageRangesDiff(
HttpRange? range = default,
string snapshot = default,
Uri previousSnapshotUri = default,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
GetPageRangesDiffInternal(
range,
snapshot,
previousSnapshot: default,
previousSnapshotUri,
conditions,
async: false,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetManagedDiskPageRangesDiff)}",
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="GetManagedDiskPageRangesDiffAsync"/>
/// operation returns the list of page ranges that differ between a
/// <paramref name="previousSnapshotUri"/> and this page blob. Changed pages
/// include both updated and cleared pages. This API only works with
/// managed disk storage accounts.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
/// Get Page Ranges</see>.
/// </summary>
/// <param name="range">
/// Optionally specifies the range of bytes over which to list ranges,
/// inclusively. If omitted, then all ranges for the blob are returned.
/// </param>
/// <param name="snapshot">
/// Optionally specifies the blob snapshot to retrieve page ranges
/// information from. For more information on working with blob snapshots,
/// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
/// Create a snapshot of a blob</see>.
/// </param>
/// <param name="previousSnapshotUri">
/// This parameter only works with managed disk storage accounts.
/// Specifies that the response will contain only pages that were
/// changed between target blob and previous snapshot. Changed pages
/// include both updated and cleared pages. The target blob may be a
/// snapshot, as long as the snapshot specified by
/// <paramref name="previousSnapshotUri"/> is the older of the two.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on getting page ranges for the this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageRangesInfo}"/> describing the
/// valid page ranges for this blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<PageRangesInfo>> GetManagedDiskPageRangesDiffAsync(
HttpRange? range = default,
string snapshot = default,
Uri previousSnapshotUri = default,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
await GetPageRangesDiffInternal(
range,
snapshot,
previousSnapshot: default,
previousSnapshotUri,
conditions,
async: true,
operationName: $"{nameof(PageBlobClient)}.{nameof(GetManagedDiskPageRangesDiff)}",
cancellationToken)
.ConfigureAwait(false);
#endregion GetManagedDiskPageRangesDiff
#region Resize
/// <summary>
/// The <see cref="Resize"/> operation resizes the page blob to
/// the specified size (which must be a multiple of 512). If the
/// specified value is less than the current size of the blob, then
/// all pages above the specified value are cleared.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
/// Set Blob Properties</see>.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary. If the specified
/// value is less than the current size of the blob, then all pages
/// above the specified value are cleared.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the resize of this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageBlobInfo}"/> describing the resized
/// page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<PageBlobInfo> Resize(
long size,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
ResizeInternal(
size,
conditions,
false, // async
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="ResizeAsync"/> operation resizes the page blob to
/// the specified size (which must be a multiple of 512). If the
/// specified value is less than the current size of the blob, then
/// all pages above the specified value are cleared.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
/// Set Blob Properties</see>.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary. If the specified
/// value is less than the current size of the blob, then all pages
/// above the specified value are cleared.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the resize of this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageBlobInfo}"/> describing the resized
/// page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<PageBlobInfo>> ResizeAsync(
long size,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
await ResizeInternal(
size,
conditions,
true, // async
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="ResizeAsync"/> operation resizes the page blob to
/// the specified size (which must be a multiple of 512). If the
/// specified value is less than the current size of the blob, then
/// all pages above the specified value are cleared.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
/// Set Blob Properties</see>.
/// </summary>
/// <param name="size">
/// Specifies the maximum size for the page blob, up to 8 TB. The
/// size must be aligned to a 512-byte boundary. If the specified
/// value is less than the current size of the blob, then all pages
/// above the specified value are cleared.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the resize of this page blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageBlobInfo}"/> describing the resized
/// page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<PageBlobInfo>> ResizeInternal(
long size,
PageBlobRequestConditions conditions,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(size)}: {size}\n" +
$"{nameof(conditions)}: {conditions}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(Resize)}");
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.Resize),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageBlobResizeHeaders> response;
if (async)
{
response = await PageBlobRestClient.ResizeAsync(
blobContentLength: size,
leaseId: conditions?.LeaseId,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.Resize(
blobContentLength: size,
leaseId: conditions?.LeaseId,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken);
}
return Response.FromValue(
response.ToPageBlobInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion Resize
#region UpdateSequenceNumber
/// <summary>
/// The <see cref="UpdateSequenceNumber"/> operation changes the
/// sequence number <paramref name="action"/> and <paramref name="sequenceNumber"/>
/// for this page blob.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
/// Set Blob Properties</see>.
/// </summary>
/// <param name="action">
/// Specifies how the service should modify the blob's sequence number.
/// <see cref="SequenceNumberAction.Max"/> sets the sequence number to
/// be the higher of the value included with the request and the value
/// currently stored for the blob. <see cref="SequenceNumberAction.Update"/>
/// sets the sequence number to the <paramref name="sequenceNumber"/>
/// value. <see cref="SequenceNumberAction.Increment"/> increments
/// the value of the sequence number by 1. If specifying
/// <see cref="SequenceNumberAction.Increment"/>, do not include the
/// <paramref name="sequenceNumber"/> because that will throw a
/// <see cref="RequestFailedException"/>.
/// </param>
/// <param name="sequenceNumber">
/// An updated sequence number of your choosing, if
/// <paramref name="action"/> is <see cref="SequenceNumberAction.Max"/>
/// or <see cref="SequenceNumberAction.Update"/>. The value should
/// not be provided if <paramref name="action"/> is
/// <see cref="SequenceNumberAction.Increment"/>. The sequence number
/// is a user-controlled property that you can use to track requests
/// and manage concurrency issues via <see cref="PageBlobRequestConditions"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add conditions
/// on updating the sequence number of this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageBlobInfo}"/> describing the updated
/// page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<PageBlobInfo> UpdateSequenceNumber(
SequenceNumberAction action,
long? sequenceNumber = default,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
UpdateSequenceNumberInternal(
action,
sequenceNumber,
conditions,
false, // async
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="UpdateSequenceNumberAsync"/> operation changes the
/// sequence number <paramref name="action"/> and <paramref name="sequenceNumber"/>
/// for this page blob.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
/// Set Blob Properties</see>.
/// </summary>
/// <param name="action">
/// Specifies how the service should modify the blob's sequence number.
/// <see cref="SequenceNumberAction.Max"/> sets the sequence number to
/// be the higher of the value included with the request and the value
/// currently stored for the blob. <see cref="SequenceNumberAction.Update"/>
/// sets the sequence number to the <paramref name="sequenceNumber"/>
/// value. <see cref="SequenceNumberAction.Increment"/> increments
/// the value of the sequence number by 1. If specifying
/// <see cref="SequenceNumberAction.Increment"/>, do not include the
/// <paramref name="sequenceNumber"/> because that will throw a
/// <see cref="RequestFailedException"/>.
/// </param>
/// <param name="sequenceNumber">
/// An updated sequence number of your choosing, if
/// <paramref name="action"/> is <see cref="SequenceNumberAction.Max"/>
/// or <see cref="SequenceNumberAction.Update"/>. The value should
/// not be provided if <paramref name="action"/> is
/// <see cref="SequenceNumberAction.Increment"/>. The sequence number
/// is a user-controlled property that you can use to track requests
/// and manage concurrency issues via <see cref="PageBlobRequestConditions"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add conditions
/// on updating the sequence number of this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageBlobInfo}"/> describing the updated
/// page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<PageBlobInfo>> UpdateSequenceNumberAsync(
SequenceNumberAction action,
long? sequenceNumber = default,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default) =>
await UpdateSequenceNumberInternal(
action,
sequenceNumber,
conditions,
true, // async
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="UpdateSequenceNumberInternal"/> operation changes the
/// sequence number <paramref name="action"/> and <paramref name="sequenceNumber"/>
/// for this page blob.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
/// Set Blob Properties</see>.
/// </summary>
/// <param name="action">
/// Specifies how the service should modify the blob's sequence number.
/// <see cref="SequenceNumberAction.Max"/> sets the sequence number to
/// be the higher of the value included with the request and the value
/// currently stored for the blob. <see cref="SequenceNumberAction.Update"/>
/// sets the sequence number to the <paramref name="sequenceNumber"/>
/// value. <see cref="SequenceNumberAction.Increment"/> increments
/// the value of the sequence number by 1. If specifying
/// <see cref="SequenceNumberAction.Increment"/>, do not include the
/// <paramref name="sequenceNumber"/> because that will throw a
/// <see cref="RequestFailedException"/>.
/// </param>
/// <param name="sequenceNumber">
/// An updated sequence number of your choosing, if
/// <paramref name="action"/> is <see cref="SequenceNumberAction.Max"/>
/// or <see cref="SequenceNumberAction.Update"/>. The value should
/// not be provided if <paramref name="action"/> is
/// <see cref="SequenceNumberAction.Increment"/>. The sequence number
/// is a user-controlled property that you can use to track requests
/// and manage concurrency issues via <see cref="PageBlobRequestConditions"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add conditions
/// on updating the sequence number of this page blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageBlobInfo}"/> describing the updated
/// page blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<PageBlobInfo>> UpdateSequenceNumberInternal(
SequenceNumberAction action,
long? sequenceNumber,
PageBlobRequestConditions conditions,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(action)}: {action}\n" +
$"{nameof(sequenceNumber)}: {sequenceNumber}\n" +
$"{nameof(conditions)}: {conditions}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(UpdateSequenceNumber)}");
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.UpdateSequenceNumber),
parameterName: nameof(conditions));
try
{
scope.Start();
ResponseWithHeaders<PageBlobUpdateSequenceNumberHeaders> response;
if (async)
{
response = await PageBlobRestClient.UpdateSequenceNumberAsync(
sequenceNumberAction: action,
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
blobSequenceNumber: sequenceNumber,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.UpdateSequenceNumber(
sequenceNumberAction: action,
leaseId: conditions?.LeaseId,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
blobSequenceNumber: sequenceNumber,
cancellationToken: cancellationToken);
}
return Response.FromValue(
response.ToPageBlobInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion UpdateSequenceNumber
#region StartCopyIncremental
/// <summary>
/// The <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// operation starts copying a snapshot of the sourceUri page blob to
/// this page blob. The snapshot is copied such that only the
/// differential changes between the previously copied snapshot are
/// transferred to the destination. The copied snapshots are complete
/// copies of the original snapshot and can be read or copied from as
/// usual. You can check the <see cref="BlobProperties.CopyStatus"/>
/// returned from the <see cref="BlobBaseClient.GetProperties"/> to
/// determine if the copy has completed.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/incremental-copy-blob">
/// Incremental Copy Blob</see> and
/// <see href="https://docs.microsoft.com/azure/virtual-machines/windows/incremental-snapshots">
/// Back up Azure unmanaged VM disks with incremental snapshots</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the to the source page blob as a <see cref="Uri"/> up to
/// 2 KB in length. The source blob must either be public or must be
/// authenticated via a shared access signature.
/// </param>
/// <param name="snapshot">
/// The name of a snapshot to start copying from
/// sourceUri.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the incremental copy into this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="CopyFromUriOperation"/> referencing the incremental
/// copy operation.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
///
/// The destination of an incremental copy must either not exist, or
/// must have been created with a previous incremental copy from the
/// same source blob. Once created, the destination blob is
/// permanently associated with the source and may only be used for
/// incremental copies.
///
/// The <see cref="BlobBaseClient.GetProperties"/>,
/// <see cref="BlobContainerClient.GetBlobs"/>, and
/// <see cref="BlobContainerClient.GetBlobsByHierarchy"/>
/// operations indicate whether the blob is an incremental copy blob
/// created in this way. Incremental copy blobs may not be downloaded
/// directly. The only supported operations are
/// <see cref="BlobBaseClient.GetProperties"/>,
/// <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>,
/// and <see cref="BlobBaseClient.Delete"/>. The copied snapshots may
/// be read and deleted as usual.
///
/// An incremental copy is performed asynchronously on the service and
/// must be polled for completion. You can poll
/// <see cref="BlobBaseClient.GetProperties"/> and check
/// <see cref="BlobProperties.CopyStatus"/> to determine when the copy
/// has completed. When the copy completes, the destination blob will
/// contain a new snapshot. The <see cref="BlobBaseClient.GetProperties"/>
/// operation returns the snapshot time of the newly created snapshot.
///
/// The first time an incremental copy is performed on a destination
/// blob, a new blob is created with a snapshot that is fully copied
/// from the source. Each subsequent call to <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// will create a new snapshot by copying only the differential
/// changes from the previously copied snapshot. The differential
/// changes are computed on the server by issuing a <see cref="GetAllPageRanges(GetPageRangesOptions, CancellationToken)"/>
/// call on the source blob snapshot with prevSnapshot set to the most
/// recently copied snapshot. Therefore, the same restrictions on
/// <see cref="GetAllPageRanges(GetPageRangesOptions, CancellationToken)"/> apply to
/// <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>.
/// Specifically, snapshots must be copied in ascending order and if
/// the source blob is recreated using <see cref="UploadPages(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> or
/// <see cref="BlobBaseClient.StartCopyFromUri(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobRequestConditions, RehydratePriority?, CancellationToken)"/>
/// then <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// on new snapshots will fail.
///
/// The additional storage space consumed by the copied snapshot is
/// the size of the differential data transferred during the copy.
/// This can be determined by performing a
/// <see cref="GetAllPageRangesDiff(GetPageRangesDiffOptions, CancellationToken)"/>
/// call on the snapshot to compare it to the previous snapshot.
/// </remarks>
public virtual CopyFromUriOperation StartCopyIncremental(
Uri sourceUri,
string snapshot,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default)
{
Response<BlobCopyInfo> response = StartCopyIncrementalInternal(
sourceUri,
snapshot,
conditions,
false, // async
cancellationToken)
.EnsureCompleted();
return new CopyFromUriOperation(
this,
response.Value.CopyId,
response.GetRawResponse(),
cancellationToken);
}
/// <summary>
/// The <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// operation starts copying a snapshot of the sourceUri page blob to
/// this page blob. The snapshot is copied such that only the
/// differential changes between the previously copied snapshot are
/// transferred to the destination. The copied snapshots are complete
/// copies of the original snapshot and can be read or copied from as
/// usual. You can check the <see cref="BlobProperties.CopyStatus"/>
/// returned from the <see cref="BlobBaseClient.GetPropertiesAsync"/>
/// to determine if thecopy has completed.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/incremental-copy-blob">
/// Incremental Copy Blob</see> and
/// <see href="https://docs.microsoft.com/azure/virtual-machines/windows/incremental-snapshots">
/// Back up Azure unmanaged VM disks with incremental snapshots</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the to the source page blob as a <see cref="Uri"/> up to
/// 2 KB in length. The source blob must either be public or must be
/// authenticated via a shared access signature.
/// </param>
/// <param name="snapshot">
/// The name of a snapshot to start copying from
/// sourceUri.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the incremental copy into this page blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="CopyFromUriOperation"/> describing the
/// state of the incremental copy operation.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
///
/// The destination of an incremental copy must either not exist, or
/// must have been created with a previous incremental copy from the
/// same source blob. Once created, the destination blob is
/// permanently associated with the source and may only be used for
/// incremental copies.
///
/// The <see cref="BlobBaseClient.GetPropertiesAsync"/>,
/// <see cref="BlobContainerClient.GetBlobsAsync"/>, and
/// <see cref="BlobContainerClient.GetBlobsByHierarchyAsync"/>
/// operations indicate whether the blob is an incremental copy blob
/// created in this way. Incremental copy blobs may not be downloaded
/// directly. The only supported operations are
/// <see cref="BlobBaseClient.GetPropertiesAsync"/>,
/// <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>,
/// and <see cref="BlobBaseClient.DeleteAsync"/>. The copied
/// snapshots may be read and deleted as usual.
///
/// An incremental copy is performed asynchronously on the service and
/// must be polled for completion. You can poll
/// <see cref="BlobBaseClient.GetPropertiesAsync"/> and check
/// <see cref="BlobProperties.CopyStatus"/> to determine when the copy
/// has completed. When the copy completes, the destination blob will
/// contain a new snapshot. The <see cref="BlobBaseClient.GetPropertiesAsync"/>
/// operation returns the snapshot time of the newly created snapshot.
///
/// The first time an incremental copy is performed on a destination
/// blob, a new blob is created with a snapshot that is fully copied
/// from the source. Each subsequent call to <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// will create a new snapshot by copying only the differential
/// changes from the previously copied snapshot. The differential
/// changes are computed on the server by issuing a <see cref="GetAllPageRangesAsync(GetPageRangesOptions, CancellationToken)"/>
/// call on the source blob snapshot with prevSnapshot set to the most
/// recently copied snapshot. Therefore, the same restrictions on
/// <see cref="GetAllPageRangesAsync(GetPageRangesOptions, CancellationToken)"/> apply to
/// <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>.
/// Specifically, snapshots must be copied in ascending order and if
/// the source blob is recreated using <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/> or
/// <see cref="BlobBaseClient.StartCopyFromUriAsync(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobRequestConditions, RehydratePriority?, CancellationToken)"/>
/// then <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// on new snapshots will fail.
///
/// The additional storage space consumed by the copied snapshot is
/// the size of the differential data transferred during the copy.
/// This can be determined by performing a
/// <see cref="GetAllPageRangesDiffAsync(GetPageRangesDiffOptions, CancellationToken)"/>
/// call on the snapshot to compare it to the previous snapshot.
/// </remarks>
public virtual async Task<CopyFromUriOperation> StartCopyIncrementalAsync(
Uri sourceUri,
string snapshot,
PageBlobRequestConditions conditions = default,
CancellationToken cancellationToken = default)
{
Response<BlobCopyInfo> response = await StartCopyIncrementalInternal(
sourceUri,
snapshot,
conditions,
true, // async
cancellationToken)
.ConfigureAwait(false);
return new CopyFromUriOperation(
this,
response.Value.CopyId,
response.GetRawResponse(),
cancellationToken);
}
/// <summary>
/// The <see cref="StartCopyIncrementalInternal"/> operation starts
/// copying a snapshot of the
/// sourceUri page blob to this page blob. The
/// snapshot is copied such that only the differential changes between
/// the previously copied snapshot are transferred to the destination.
/// The copied snapshots are complete copies of the original snapshot
/// and can be read or copied from as usual. You can check the
/// <see cref="BlobProperties.CopyStatus"/> returned from the
/// <see cref="BlobBaseClient.GetPropertiesAsync"/> to determine if the
/// copy has completed.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/incremental-copy-blob">
/// Incremental Copy Blob</see> and
/// <see href="https://docs.microsoft.com/azure/virtual-machines/windows/incremental-snapshots">
/// Back up Azure unmanaged VM disks with incremental snapshots</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the to the source page blob as a <see cref="Uri"/> up to
/// 2 KB in length. The source blob must either be public or must be
/// authenticated via a shared access signature.
/// </param>
/// <param name="snapshot">
/// The name of a snapshot to start copying from
/// sourceUri.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the incremental copy into this page blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{BlobCopyInfo}"/> describing the
/// state of the incremental copy operation.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
///
/// The destination of an incremental copy must either not exist, or
/// must have been created with a previous incremental copy from the
/// same source blob. Once created, the destination blob is
/// permanently associated with the source and may only be used for
/// incremental copies.
///
/// The <see cref="BlobBaseClient.GetPropertiesAsync"/>,
/// <see cref="BlobContainerClient.GetBlobsAsync"/>, and
/// <see cref="BlobContainerClient.GetBlobsByHierarchyAsync"/>
/// operations indicate whether the blob is an incremental copy blob
/// created in this way. Incremental copy blobs may not be downloaded
/// directly. The only supported operations are
/// <see cref="BlobBaseClient.GetPropertiesAsync"/>,
/// <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>,
/// and <see cref="BlobBaseClient.DeleteAsync"/>. The copied
/// snapshots may be read and deleted as usual.
///
/// An incremental copy is performed asynchronously on the service and
/// must be polled for completion. You can poll
/// <see cref="BlobBaseClient.GetPropertiesAsync"/> and check
/// <see cref="BlobProperties.CopyStatus"/> to determine when the copy
/// has completed. When the copy completes, the destination blob will
/// contain a new snapshot. The <see cref="BlobBaseClient.GetPropertiesAsync"/>
/// operation returns the snapshot time of the newly created snapshot.
///
/// The first time an incremental copy is performed on a destination
/// blob, a new blob is created with a snapshot that is fully copied
/// from the source. Each subsequent call to <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// will create a new snapshot by copying only the differential
/// changes from the previously copied snapshot. The differential
/// changes are computed on the server by issuing a <see cref="GetAllPageRangesAsync(GetPageRangesOptions, CancellationToken)"/>
/// call on the source blob snapshot with prevSnapshot set to the most
/// recently copied snapshot. Therefore, the same restrictions on
/// <see cref="GetAllPageRangesAsync(GetPageRangesOptions, CancellationToken)"/> apply to
/// <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>.
/// Specifically, snapshots must be copied in ascending order and if
/// the source blob is recreated using <see cref="UploadPagesAsync(Stream, long, byte[], PageBlobRequestConditions, IProgress{long}, CancellationToken)"/>
/// or <see cref="BlobBaseClient.StartCopyFromUriAsync(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobRequestConditions, RehydratePriority?, CancellationToken)"/>
/// then <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
/// on new snapshots will fail.
///
/// The additional storage space consumed by the copied snapshot is
/// the size of the differential data transferred during the copy.
/// This can be determined by performing a
/// <see cref="GetPageRangesDiffInternal"/>
/// call on the snapshot to compare it to the previous snapshot.
/// </remarks>
private async Task<Response<BlobCopyInfo>> StartCopyIncrementalInternal(
Uri sourceUri,
string snapshot,
PageBlobRequestConditions conditions,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(sourceUri)}: {sourceUri}\n" +
$"{nameof(snapshot)}: {snapshot}\n" +
$"{nameof(conditions)}: {conditions}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(StartCopyIncremental)}");
conditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.LeaseId
| BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual,
operationName: nameof(PageBlobClient.StartCopyIncremental),
parameterName: nameof(conditions));
try
{
scope.Start();
// Create copySource Uri
PageBlobClient sourcePageBlobClient = new PageBlobClient(
sourceUri,
ClientConfiguration).WithSnapshot(snapshot);
ResponseWithHeaders<PageBlobCopyIncrementalHeaders> response;
if (async)
{
response = await PageBlobRestClient.CopyIncrementalAsync(
copySource: sourcePageBlobClient.Uri.AbsoluteUri,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.CopyIncremental(
copySource: sourcePageBlobClient.Uri.AbsoluteUri,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
cancellationToken: cancellationToken);
}
return Response.FromValue(
response.ToBlobCopyInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion StartCopyIncremental
#region UploadPagesFromUri
/// <summary>
/// The <see cref="UploadPagesFromUri(Uri, HttpRange, HttpRange, PageBlobUploadPagesFromUriOptions, CancellationToken)"/>
/// operation writes a range of pages to a page blob where the contents are read from
/// sourceUri.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
/// Put Page From URL</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the <see cref="Uri"/> of the source blob. The value may
/// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
/// blob. The source blob must either be public or must be
/// authenticated via a shared access signature. If the source blob
/// is public, no authentication is required to perform the operation.
/// </param>
/// <param name="sourceRange">
/// Optionally only upload the bytes of the blob in the
/// sourceUri in the specified range.
/// </param>
/// <param name="range">
/// Specifies the range to be written as a page. Both the start and
/// end of the range must be specified and can be up to 4MB in size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="options">
/// Optional parameters. <see cref="PageBlobUploadPagesFromUriOptions"/>.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual Response<PageInfo> UploadPagesFromUri(
Uri sourceUri,
HttpRange sourceRange,
HttpRange range,
PageBlobUploadPagesFromUriOptions options = default,
CancellationToken cancellationToken = default) =>
UploadPagesFromUriInternal(
sourceUri,
sourceRange,
range,
options?.SourceContentHash,
options?.DestinationConditions,
options?.SourceConditions,
options?.SourceAuthentication,
options?.SourceShareTokenIntent,
async: false,
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="UploadPagesFromUriAsync(Uri, HttpRange, HttpRange, PageBlobUploadPagesFromUriOptions, CancellationToken)"/>
/// operation writes a range of pages to a page blob where the contents are read from
/// sourceUri.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
/// Put Page From URL</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the <see cref="Uri"/> of the source blob. The value may
/// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
/// blob. The source blob must either be public or must be
/// authenticated via a shared access signature. If the source blob
/// is public, no authentication is required to perform the operation.
/// </param>
/// <param name="sourceRange">
/// Optionally only upload the bytes of the blob in the
/// sourceUri in the specified range.
/// </param>
/// <param name="range">
/// Specifies the range to be written as a page. Both the start and
/// end of the range must be specified and can be up to 4MB in size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="options">
/// Optional parameters. <see cref="PageBlobUploadPagesFromUriOptions"/>.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
public virtual async Task<Response<PageInfo>> UploadPagesFromUriAsync(
Uri sourceUri,
HttpRange sourceRange,
HttpRange range,
PageBlobUploadPagesFromUriOptions options = default,
CancellationToken cancellationToken = default) =>
await UploadPagesFromUriInternal(
sourceUri,
sourceRange,
range,
options?.SourceContentHash,
options?.DestinationConditions,
options?.SourceConditions,
options?.SourceAuthentication,
options?.SourceShareTokenIntent,
async: true,
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="UploadPagesFromUri(Uri, HttpRange, HttpRange, byte[], PageBlobRequestConditions, PageBlobRequestConditions, CancellationToken)"/>
/// operation writes a range of pages to a page blob where the contents are read from
/// sourceUri.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
/// Put Page From URL</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the <see cref="Uri"/> of the source blob. The value may
/// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
/// blob. The source blob must either be public or must be
/// authenticated via a shared access signature. If the source blob
/// is public, no authentication is required to perform the operation.
/// </param>
/// <param name="sourceRange">
/// Optionally only upload the bytes of the blob in the
/// sourceUri in the specified range.
/// </param>
/// <param name="range">
/// Specifies the range to be written as a page. Both the start and
/// end of the range must be specified and can be up to 4MB in size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="sourceContentHash">
/// Optional MD5 hash of the page block content from the
/// sourceUri. This hash is used to verify the
/// integrity of the block during transport of the data from the Uri.
/// When this hash is specified, the storage service compares the hash
/// of the content that has arrived from the sourceUri
/// with this value. Note that this md5 hash is not stored with the
/// blob. If the two hashes do not match, the operation will fail
/// with a <see cref="RequestFailedException"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the copying of data to this page blob.
/// </param>
/// <param name="sourceConditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the copying of data from this source blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
#pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
public virtual Response<PageInfo> UploadPagesFromUri(
#pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
Uri sourceUri,
HttpRange sourceRange,
HttpRange range,
byte[] sourceContentHash,
PageBlobRequestConditions conditions,
PageBlobRequestConditions sourceConditions,
CancellationToken cancellationToken) =>
UploadPagesFromUriInternal(
sourceUri,
sourceRange,
range,
sourceContentHash,
conditions,
sourceConditions,
sourceAuthentication: default,
sourceTokenIntent: default,
async: false,
cancellationToken)
.EnsureCompleted();
/// <summary>
/// The <see cref="UploadPagesFromUriAsync(Uri, HttpRange, HttpRange, byte[], PageBlobRequestConditions, PageBlobRequestConditions, CancellationToken)"/>
/// operation writes a range of pages to a page blob where the contents are read from
/// sourceUri.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
/// Put Page From URL</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the <see cref="Uri"/> of the source blob. The value may
/// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
/// blob. The source blob must either be public or must be
/// authenticated via a shared access signature. If the source blob
/// is public, no authentication is required to perform the operation.
/// </param>
/// <param name="sourceRange">
/// Optionally only upload the bytes of the blob in the
/// sourceUri in the specified range.
/// </param>
/// <param name="range">
/// Specifies the range to be written as a page. Both the start and
/// end of the range must be specified and can be up to 4MB in size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="sourceContentHash">
/// Optional MD5 hash of the page block content from the
/// sourceUri. This hash is used to verify the
/// integrity of the block during transport of the data from the Uri.
/// When this hash is specified, the storage service compares the hash
/// of the content that has arrived from the sourceUri
/// with this value. Note that this md5 hash is not stored with the
/// blob. If the two hashes do not match, the operation will fail
/// with a <see cref="RequestFailedException"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the copying of data to this page blob.
/// </param>
/// <param name="sourceConditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the copying of data from this source blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
#pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
public virtual async Task<Response<PageInfo>> UploadPagesFromUriAsync(
#pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
Uri sourceUri,
HttpRange sourceRange,
HttpRange range,
byte[] sourceContentHash,
PageBlobRequestConditions conditions,
PageBlobRequestConditions sourceConditions,
CancellationToken cancellationToken) =>
await UploadPagesFromUriInternal(
sourceUri,
sourceRange,
range,
sourceContentHash,
conditions,
sourceConditions,
sourceAuthentication: default,
sourceTokenIntent: default,
async: true,
cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// The <see cref="UploadPagesFromUriInternal"/> operation writes a
/// range of pages to a page blob where the contents are read from
/// sourceUri.
///
/// For more information, see
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
/// Put Page From URL</see>.
/// </summary>
/// <param name="sourceUri">
/// Specifies the <see cref="Uri"/> of the source blob. The value may
/// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
/// blob. The source blob must either be public or must be
/// authenticated via a shared access signature. If the source blob
/// is public, no authentication is required to perform the operation.
/// </param>
/// <param name="sourceRange">
/// Optionally only upload the bytes of the blob in the
/// sourceUri in the specified range.
/// </param>
/// <param name="range">
/// Specifies the range to be written as a page. Both the start and
/// end of the range must be specified and can be up to 4MB in size.
/// Given that pages must be aligned with 512-byte boundaries, the
/// start of the range must be a modulus of 512 and the end of the
/// range must be a modulus of 512 – 1. Examples of valid byte ranges
/// are 0-511, 512-1023, etc.
/// </param>
/// <param name="sourceContentHash">
/// Optional MD5 hash of the page block content from the
/// sourceUri. This hash is used to verify the
/// integrity of the block during transport of the data from the Uri.
/// When this hash is specified, the storage service compares the hash
/// of the content that has arrived from the sourceUri
/// with this value. Note that this md5 hash is not stored with the
/// blob. If the two hashes do not match, the operation will fail
/// with a <see cref="RequestFailedException"/>.
/// </param>
/// <param name="conditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the copying of data to this page blob.
/// </param>
/// <param name="sourceConditions">
/// Optional <see cref="PageBlobRequestConditions"/> to add
/// conditions on the copying of data from this source blob.
/// </param>
/// <param name="sourceAuthentication">
/// Optional. Source authentication used to access the source blob.
/// </param>
/// <param name="sourceTokenIntent">
/// Optional, only applicable (but required) when the source is Azure Storage Files and using token authentication.
/// Used to indicate the intent of the request.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{PageInfo}"/> describing the
/// state of the updated pages.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
/// </remarks>
private async Task<Response<PageInfo>> UploadPagesFromUriInternal(
Uri sourceUri,
HttpRange sourceRange,
HttpRange range,
byte[] sourceContentHash,
PageBlobRequestConditions conditions,
PageBlobRequestConditions sourceConditions,
HttpAuthorization sourceAuthentication,
FileShareTokenIntent? sourceTokenIntent,
bool async,
CancellationToken cancellationToken)
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
{
ClientConfiguration.Pipeline.LogMethodEnter(
nameof(PageBlobClient),
message:
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(sourceUri)}: {sourceUri}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(UploadPagesFromUri)}");
// All destination PageBlobRequestConditions are valid.
conditions.ValidateConditionsNotPresent(
invalidConditions: BlobRequestConditionProperty.None,
operationName: nameof(PageBlobClient.UploadPagesFromUri),
parameterName: nameof(conditions));
sourceConditions.ValidateConditionsNotPresent(
invalidConditions:
BlobRequestConditionProperty.LeaseId
| BlobRequestConditionProperty.IfSequenceNumberLessThanOrEqual
| BlobRequestConditionProperty.IfSequenceNumberLessThan
| BlobRequestConditionProperty.IfSequenceNumberEqual
| BlobRequestConditionProperty.TagConditions,
operationName: nameof(PageBlobClient.UploadPagesFromUri),
parameterName: nameof(sourceConditions));
try
{
scope.Start();
ResponseWithHeaders<PageBlobUploadPagesFromURLHeaders> response;
if (async)
{
response = await PageBlobRestClient.UploadPagesFromURLAsync(
sourceUrl: sourceUri.AbsoluteUri,
sourceRange: sourceRange.ToString(),
contentLength: 0,
range: range.ToString(),
sourceContentMD5: sourceContentHash,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
encryptionScope: ClientConfiguration.EncryptionScope,
leaseId: conditions?.LeaseId,
ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
sourceIfMatch: sourceConditions?.IfMatch?.ToString(),
sourceIfNoneMatch: sourceConditions?.IfNoneMatch?.ToString(),
copySourceAuthorization: sourceAuthentication?.ToString(),
fileRequestIntent: sourceTokenIntent,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
else
{
response = PageBlobRestClient.UploadPagesFromURL(
sourceUrl: sourceUri.AbsoluteUri,
sourceRange: sourceRange.ToString(),
contentLength: 0,
range: range.ToString(),
sourceContentMD5: sourceContentHash,
encryptionKey: ClientConfiguration.CustomerProvidedKey?.EncryptionKey,
encryptionKeySha256: ClientConfiguration.CustomerProvidedKey?.EncryptionKeyHash,
encryptionAlgorithm: ClientConfiguration.CustomerProvidedKey?.EncryptionAlgorithm == null ? null : EncryptionAlgorithmTypeInternal.AES256,
encryptionScope: ClientConfiguration.EncryptionScope,
leaseId: conditions?.LeaseId,
ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
ifModifiedSince: conditions?.IfModifiedSince,
ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
ifMatch: conditions?.IfMatch?.ToString(),
ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
ifTags: conditions?.TagConditions,
sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
sourceIfMatch: sourceConditions?.IfMatch?.ToString(),
sourceIfNoneMatch: sourceConditions?.IfNoneMatch?.ToString(),
copySourceAuthorization: sourceAuthentication?.ToString(),
fileRequestIntent: sourceTokenIntent,
cancellationToken: cancellationToken);
}
return Response.FromValue(
response.ToPageInfo(),
response.GetRawResponse());
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(PageBlobClient));
scope.Dispose();
}
}
}
#endregion UploadPagesFromUri
#region OpenWrite
/// <summary>
/// Opens a stream for writing to the blob.
/// </summary>
/// <param name="overwrite">
/// Whether an existing blob should be deleted and recreated.
/// </param>
/// <param name="position">
/// The offset within the blob to begin writing from.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A stream to write to the Page Blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
///
/// During the disposal of the returned write stream, an exception may be thrown.
/// </remarks>
#pragma warning disable AZC0015 // Unexpected client method return type.
public virtual Stream OpenWrite(
#pragma warning restore AZC0015 // Unexpected client method return type.
bool overwrite,
long position,
PageBlobOpenWriteOptions options = default,
CancellationToken cancellationToken = default)
=> OpenWriteInternal(
overwrite: overwrite,
position: position,
options: options,
async: false,
cancellationToken: cancellationToken)
.EnsureCompleted();
/// <summary>
/// Opens a stream for writing to the blob.
/// </summary>
/// <param name="overwrite">
/// Whether an existing blob should be deleted and recreated.
/// </param>
/// <param name="position">
/// The offset within the blob to begin writing from.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A stream to write to the Page Blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
///
/// During the disposal of the returned write stream, an exception may be thrown.
/// </remarks>
#pragma warning disable AZC0015 // Unexpected client method return type.
public virtual async Task<Stream> OpenWriteAsync(
#pragma warning restore AZC0015 // Unexpected client method return type.
bool overwrite,
long position,
PageBlobOpenWriteOptions options = default,
CancellationToken cancellationToken = default)
=> await OpenWriteInternal(
overwrite: overwrite,
position: position,
options: options,
async: true,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// Opens a stream for writing to the blob.
/// </summary>
/// <param name="overwrite">
/// Whether an existing blob should be deleted and recreated.
/// </param>
/// <param name="position">
/// The offset within the page blob to begin writing from.
/// </param>
/// <param name="options">
/// Optional parameters.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A stream to write to the Page Blob.
/// </returns>
/// <remarks>
/// A <see cref="RequestFailedException"/> will be thrown if
/// a failure occurs.
/// If multiple failures occur, an <see cref="AggregateException"/> will be thrown,
/// containing each failure instance.
///
/// During the disposal of the returned write stream, an exception may be thrown.
/// </remarks>
private async Task<Stream> OpenWriteInternal(
bool overwrite,
long position,
PageBlobOpenWriteOptions options,
bool async,
CancellationToken cancellationToken)
{
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(PageBlobClient)}.{nameof(OpenWrite)}");
try
{
scope.Start();
ETag? etag;
if (overwrite)
{
if (options?.Size == null)
{
throw new ArgumentException($"{nameof(options)}.{nameof(options.Size)} must be set if {nameof(overwrite)} is set to true");
}
Response<BlobContentInfo> createResponse = await CreateInternal(
size: options.Size.Value,
sequenceNumber: default,
httpHeaders: default,
metadata: default,
tags: default,
conditions: options?.OpenConditions,
immutabilityPolicy: default,
legalHold: default,
premiumPageBlobAccessTier: default,
async: async,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
etag = createResponse.Value.ETag;
}
else
{
try
{
Response<BlobProperties> propertiesResponse = await GetPropertiesInternal(
conditions: options?.OpenConditions,
async: async,
context: new RequestContext() { CancellationToken = cancellationToken })
.ConfigureAwait(false);
etag = propertiesResponse.Value.ETag;
}
catch (RequestFailedException ex)
when (ex.ErrorCode == BlobErrorCode.BlobNotFound)
{
if (options?.Size == null)
{
throw new ArgumentException($"{nameof(options)}.{nameof(options.Size)} must be set if the Page Blob is being created for the first time");
}
Response<BlobContentInfo> createResponse = await CreateInternal(
size: options.Size.Value,
sequenceNumber: default,
httpHeaders: default,
metadata: default,
tags: default,
conditions: options?.OpenConditions,
immutabilityPolicy: default,
legalHold: default,
premiumPageBlobAccessTier: default,
async: async,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
etag = createResponse.Value.ETag;
}
}
PageBlobRequestConditions conditions = new PageBlobRequestConditions()
{
IfMatch = etag,
LeaseId = options?.OpenConditions?.LeaseId,
};
return new PageBlobWriteStream(
pageBlobClient: this,
bufferSize: options?.BufferSize ?? Constants.DefaultBufferSize,
position: position,
conditions: conditions,
progressHandler: options?.ProgressHandler,
options?.TransferValidation ?? ClientConfiguration.TransferValidation.Upload
);
}
catch (Exception ex)
{
scope.Failed(ex);
throw;
}
finally
{
scope.Dispose();
}
}
#endregion OpenWrite
}
/// <summary>
/// Add easy to discover methods to <see cref="BlobContainerClient"/> for
/// creating <see cref="PageBlobClient"/> instances.
/// </summary>
public static partial class SpecializedBlobExtensions
{
/// <summary>
/// Create a new <see cref="PageBlobClient"/> object by
/// concatenating <paramref name="blobName"/> to
/// the end of the <paramref name="client"/>'s
/// <see cref="BlobContainerClient.Uri"/>. The new
/// <see cref="PageBlobClient"/>
/// uses the same request policy pipeline as the
/// <see cref="BlobContainerClient"/>.
/// </summary>
/// <param name="client">The <see cref="BlobContainerClient"/>.</param>
/// <param name="blobName">The name of the page blob.</param>
/// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
public static PageBlobClient GetPageBlobClient(
this BlobContainerClient client,
string blobName)
{
return client.GetPageBlobClientCore(blobName);
}
}
}