diff --git a/sdk/core/Azure.Core/src/Shared/RequestContextExtensions.cs b/sdk/core/Azure.Core/src/Shared/RequestContextExtensions.cs
new file mode 100644
index 0000000000000..22103bff18332
--- /dev/null
+++ b/sdk/core/Azure.Core/src/Shared/RequestContextExtensions.cs
@@ -0,0 +1,159 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Threading;
+
+namespace Azure.Core
+{
+ ///
+ /// Shared source helpers for .
+ ///
+ internal static class RequestContextExtensions
+ {
+ ///
+ /// Singleton to use when we don't have an
+ /// instance.
+ ///
+ public static RequestContext Empty { get; } = new RequestContext();
+
+ ///
+ /// Create a RequestContext instance from a CancellationToken.
+ ///
+ /// The cancellation token.
+ ///
+ /// A wrapping the cancellation token.
+ ///
+ public static RequestContext ToRequestContext(this CancellationToken cancellationToken) =>
+ cancellationToken == CancellationToken.None ?
+ Empty :
+ new() { CancellationToken = cancellationToken };
+
+ ///
+ /// Link a CancellationToken with an existing RequestContext.
+ ///
+ ///
+ /// The for the current operation.
+ ///
+ /// A cancellation token.
+ ///
+ /// The for the current operation.
+ ///
+ public static RequestContext Link(this RequestContext context, CancellationToken cancellationToken)
+ {
+ if (cancellationToken == CancellationToken.None)
+ {
+ // Don't link if there's nothing there
+ }
+ else if (context.CancellationToken == CancellationToken.None)
+ {
+ // Don't link if we can just replace
+ context.CancellationToken = cancellationToken;
+ }
+ else
+ {
+ // Otherwise link them together
+ CancellationTokenSource source = CancellationTokenSource.CreateLinkedTokenSource(
+ context.CancellationToken,
+ cancellationToken);
+ context.CancellationToken = source.Token;
+ }
+ return context;
+ }
+
+ ///
+ /// Customizes the for this operation
+ /// to change the default classification behavior
+ /// so that it evalutes the anonymous classifier to determine whether
+ /// an error occured or not.
+ ///
+ /// Custom classifiers are applied after all
+ /// classifiers. This is
+ /// useful for cases where you'd like to prevent specific situations
+ /// from being treated as errors by logging and distributed tracing
+ /// policies -- that is, if a response is not classified as an error,
+ /// it will not appear as an error in logs or distributed traces.
+ ///
+ ///
+ /// The for the current operation.
+ ///
+ ///
+ /// A function to classify the response. It should return true if the
+ /// message contains an error, false if not an error, and null if it
+ /// was unable to classify.
+ ///
+ ///
+ /// The for the current operation.
+ ///
+ public static RequestContext AddClassifier(this RequestContext context, Func classifier)
+ {
+ Argument.AssertNotNull(context, nameof(context));
+ Argument.AssertNotNull(classifier, nameof(classifier));
+ context.AddClassifier(new LambdaClassifier(classifier));
+ return context;
+ }
+
+ // Anonymous reponse classifier
+ private class LambdaClassifier : ResponseClassificationHandler
+ {
+ private Func _classifier;
+
+ public LambdaClassifier(Func classifier) =>
+ _classifier = classifier;
+
+ public override bool TryClassify(HttpMessage message, out bool isError)
+ {
+ if (message.HasResponse)
+ {
+ bool? result = _classifier(message);
+ if (result is not null)
+ {
+ isError = result.Value;
+ return true;
+ }
+ }
+
+ isError = false;
+ return false;
+ }
+ }
+
+ ///
+ /// Customizes the for this operation
+ /// to change the default classification behavior
+ /// so that it considers the passed-in status code and error code to be
+ /// an error or not, as specified.
+ ///
+ /// Custom classifiers are applied after all
+ /// classifiers. This is
+ /// useful for cases where you'd like to prevent specific response
+ /// status and error codes from being treated as errors by logging and
+ /// distributed tracing policies -- that is, if a response is not
+ /// classified as an error, it will not appear as an error in logs or
+ /// distributed traces.
+ ///
+ ///
+ /// The for the current operation.
+ ///
+ ///
+ /// The status code to customize classification for.
+ ///
+ ///
+ /// The error code to customize classification for.
+ ///
+ ///
+ /// Whether the passed-in status code should be classified as an error.
+ ///
+ ///
+ /// The for the current operation.
+ ///
+ public static RequestContext AddClassifier(this RequestContext context, int statusCode, string errorCode, bool isError) =>
+ context.AddClassifier(
+ message =>
+ message.Response.Status == statusCode &&
+ message.Response.Headers.TryGetValue("x-ms-error-code", out string code) &&
+ code == errorCode ?
+ isError :
+ null);
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs
index da34d72a92a56..05668ed8f97fe 100644
--- a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs
+++ b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs
@@ -1578,7 +1578,9 @@ public BlobLeaseClient(Azure.Storage.Blobs.Specialized.BlobBaseClient client, st
protected virtual Azure.Storage.Blobs.BlobContainerClient BlobContainerClient { get { throw null; } }
public virtual string LeaseId { get { throw null; } }
public System.Uri Uri { get { throw null; } }
+ public virtual Azure.Response Acquire(System.TimeSpan duration, Azure.RequestConditions conditions, Azure.RequestContext context) { throw null; }
public virtual Azure.Response Acquire(System.TimeSpan duration, Azure.RequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public virtual System.Threading.Tasks.Task> AcquireAsync(System.TimeSpan duration, Azure.RequestConditions conditions, Azure.RequestContext context) { throw null; }
public virtual System.Threading.Tasks.Task> AcquireAsync(System.TimeSpan duration, Azure.RequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.Response Break(System.TimeSpan? breakPeriod = default(System.TimeSpan?), Azure.RequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual System.Threading.Tasks.Task> BreakAsync(System.TimeSpan? breakPeriod = default(System.TimeSpan?), Azure.RequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
diff --git a/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj b/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj
index f6dac3e6598a5..44917118a0be8 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj
+++ b/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj
@@ -35,6 +35,7 @@
+
diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs
index f9adcabefcd94..cab2ae59645ec 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs
+++ b/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs
@@ -4442,39 +4442,59 @@ private async Task> ExistsInternal(
nameof(BlobBaseClient),
message:
$"{nameof(Uri)}: {Uri}");
-
- string operationName = $"{nameof(BlobBaseClient)}.{nameof(Exists)}";
-
+ DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(BlobBaseClient)}.{nameof(Exists)}");
try
{
- Response response = await GetPropertiesInternal(
- conditions: default,
- async: async,
- cancellationToken: cancellationToken,
- operationName)
- .ConfigureAwait(false);
+ scope.Start();
- return Response.FromValue(true, response.GetRawResponse());
- }
- catch (RequestFailedException storageRequestFailedException)
- when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobNotFound
- || storageRequestFailedException.ErrorCode == BlobErrorCode.ContainerNotFound)
- {
- return Response.FromValue(false, default);
- }
- catch (RequestFailedException storageRequestFailedException)
- when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobUsesCustomerSpecifiedEncryption)
- {
- return Response.FromValue(true, default);
+ // Get the blob properties, but don't throw any exceptions
+ RequestContext context =
+ new RequestContext()
+ {
+ ErrorOptions = ErrorOptions.NoThrow,
+ CancellationToken = cancellationToken
+ }
+ .AddClassifier(404, BlobErrorCode.BlobNotFound.ToString(), false)
+ .AddClassifier(404, BlobErrorCode.ContainerNotFound.ToString(), false)
+ .AddClassifier(409, BlobErrorCode.BlobUsesCustomerSpecifiedEncryption.ToString(), false);
+ Response response = async ?
+ await BlobRestClient.GetPropertiesAsync(context: context).ConfigureAwait(false) :
+ BlobRestClient.GetProperties(context: context);
+
+ // If the response was any error other than a 404
+ // ContainerNotFound, 404 BlobNotFound, or 409
+ // BlobUsesCustomerSpecifiedEncryption we will throw
+ if (response.IsError)
+ {
+ RequestFailedException ex = async ?
+ await ClientConfiguration.ClientDiagnostics.CreateRequestFailedExceptionAsync(response).ConfigureAwait(false) :
+ ClientConfiguration.ClientDiagnostics.CreateRequestFailedException(response);
+ // Can't simply do the following because of https://github.com/Azure/azure-sdk-for-net/issues/27614
+ // ex = new RequestFailedException(response);
+
+ throw ex;
+ }
+
+ return Response.FromValue(
+ response.Status switch
+ {
+ 200 => true, // Blob found
+ 409 => true, // GetProperties failed because of encryption so blob exists
+ 404 => false, // Blob not found
+ _ => false // Otherwise consider it not found
+ },
+ response);
}
catch (Exception ex)
{
ClientConfiguration.Pipeline.LogException(ex);
+ scope.Failed(ex);
throw;
}
finally
{
ClientConfiguration.Pipeline.LogMethodExit(nameof(BlobBaseClient));
+ scope.Dispose();
}
}
}
diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs
index 095683f88bfab..bc7aac2b332b7 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs
+++ b/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs
@@ -1595,28 +1595,41 @@ private async Task> ExistsInternal(
{
using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(BlobContainerClient)))
{
- ClientConfiguration.Pipeline.LogMethodEnter(
- nameof(BlobContainerClient),
- message:
- $"{nameof(Uri)}: {Uri}");
-
+ ClientConfiguration.Pipeline.LogMethodEnter(nameof(BlobContainerClient), message: $"{nameof(Uri)}: {Uri}");
DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(BlobContainerClient)}.{nameof(Exists)}");
- scope.Start();
-
try
{
- Response response = await GetPropertiesInternal(
- conditions: null,
- async: async,
- cancellationToken: cancellationToken)
- .ConfigureAwait(false);
+ scope.Start();
- return Response.FromValue(true, response.GetRawResponse());
- }
- catch (RequestFailedException storageRequestFailedException)
- when (storageRequestFailedException.ErrorCode == BlobErrorCode.ContainerNotFound)
- {
- return Response.FromValue(false, default);
+ // Get the container properties without throwing any exceptions
+ RequestContext context =
+ new RequestContext()
+ {
+ ErrorOptions = ErrorOptions.NoThrow,
+ CancellationToken = cancellationToken
+ }
+ .AddClassifier(404, BlobErrorCode.ContainerNotFound.ToString(), false);
+
+ Response response = async ?
+ await ContainerRestClient.GetPropertiesAsync(context: context).ConfigureAwait(false) :
+ ContainerRestClient.GetProperties(context: context);
+
+ // If the response was any error other than a 404
+ // ContainerNotFound we will throw.
+ if (response.IsError)
+ {
+ RequestFailedException ex = async ?
+ await ClientConfiguration.ClientDiagnostics.CreateRequestFailedExceptionAsync(response).ConfigureAwait(false) :
+ ClientConfiguration.ClientDiagnostics.CreateRequestFailedException(response);
+ // Can't simply do the following because of https://github.com/Azure/azure-sdk-for-net/issues/27614
+ // ex = new RequestFailedException(response);
+
+ throw ex;
+ }
+
+ // The container exists if we returned 200, but a 404 means
+ // it doesn't
+ return Response.FromValue(response.Status == 200, response);
}
catch (Exception ex)
{
diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobLeaseClient.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobLeaseClient.cs
index 15d32f3654e66..0e32469829d28 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/BlobLeaseClient.cs
+++ b/sdk/storage/Azure.Storage.Blobs/src/BlobLeaseClient.cs
@@ -141,9 +141,10 @@ private void EnsureClient()
#region Acquire
///
- /// The operation acquires a lease on
- /// the blob or container. The lease must
- /// be between 15 to 60 seconds, or infinite (-1).
+ /// The
+ /// operation acquires a lease on the blob or container. The lease
+ /// must be between 15 to 60 seconds, or
+ /// infinite (-1).
///
/// If the container does not have an active lease, the Blob service
/// creates a lease on the blob or container and returns it. If the
@@ -184,13 +185,15 @@ public virtual Response Acquire(
duration,
conditions,
async: false,
- cancellationToken)
+ protocol: false,
+ cancellationToken: cancellationToken)
.EnsureCompleted();
///
- /// The operation acquires a lease on
- /// the blob or container. The lease must
- /// be between 15 to 60 seconds, or infinite (-1).
+ /// The
+ /// operation acquires a lease on the blob or container. The lease
+ /// must be between 15 to 60 seconds, or
+ /// infinite (-1).
///
/// If the container does not have an active lease, the Blob service
/// creates a lease on the blob or container and returns it. If the
@@ -232,8 +235,112 @@ await AcquireInternal(
duration,
conditions,
async: true,
- cancellationToken)
+ protocol: false,
+ cancellationToken: cancellationToken)
+ .ConfigureAwait(false);
+
+ ///
+ /// The
+ /// operation acquires a lease on the blob or container. The lease
+ /// must be between 15 to 60 seconds, or
+ /// infinite (-1).
+ ///
+ /// If the container does not have an active lease, the Blob service
+ /// creates a lease on the blob or container and returns it. If the
+ /// container has an active lease, you can only request a new lease
+ /// using the active lease ID as , but you can
+ /// specify a new .
+ ///
+ /// For more information, see
+ /// Lease Container.
+ ///
+ ///
+ /// Specifies the duration of the lease, in seconds, or specify
+ /// for a lease that never expires.
+ /// A non-infinite lease can be between 15 and 60 seconds.
+ /// A lease duration cannot be changed using
+ /// or .
+ ///
+ ///
+ /// Optional to add
+ /// conditions on acquiring a lease.
+ ///
+ ///
+ /// Optional to to control the behavior of
+ /// this request.
+ ///
+ ///
+ /// A describing the lease.
+ ///
+ ///
+ /// A will be thrown if
+ /// a failure occurs.
+ ///
+#pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
+ public virtual Response Acquire(
+ TimeSpan duration,
+ RequestConditions conditions,
+ RequestContext context) =>
+ AcquireInternal(
+ duration,
+ conditions,
+ async: false,
+ protocol: true,
+ context: context)
+ .EnsureCompleted();
+#pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
+
+ ///
+ /// The
+ /// operation acquires a lease on the blob or container. The lease
+ /// must be between 15 to 60 seconds, or
+ /// infinite (-1).
+ ///
+ /// If the container does not have an active lease, the Blob service
+ /// creates a lease on the blob or container and returns it. If the
+ /// container has an active lease, you can only request a new lease
+ /// using the active lease ID as , but you can
+ /// specify a new .
+ ///
+ /// For more information, see
+ ///
+ /// Lease Container.
+ ///
+ ///
+ /// Specifies the duration of the lease, in seconds, or specify
+ /// for a lease that never expires.
+ /// A non-infinite lease can be between 15 and 60 seconds.
+ /// A lease duration cannot be changed using
+ /// or .
+ ///
+ ///
+ /// Optional to add
+ /// conditions on acquiring a lease.
+ ///
+ ///
+ /// Optional to to control the behavior of
+ /// this request.
+ ///
+ ///
+ /// A describing the lease.
+ ///
+ ///
+ /// A will be thrown if
+ /// a failure occurs.
+ ///
+#pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
+ public virtual async Task> AcquireAsync(
+ TimeSpan duration,
+ RequestConditions conditions,
+ RequestContext context) =>
+ await AcquireInternal(
+ duration,
+ conditions,
+ async: true,
+ protocol: true,
+ context: context)
.ConfigureAwait(false);
+#pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.
///
/// The operation acquires a lease on
@@ -264,6 +371,13 @@ await AcquireInternal(
///
/// Whether to invoke the operation asynchronously.
///
+ ///
+ /// Whether to invoke the protocol method.
+ ///
+ ///
+ /// Optional to to control the behavior of
+ /// this request.
+ ///
///
/// Optional to propagate
/// notifications that the operation should be cancelled.
@@ -279,7 +393,9 @@ private async Task> AcquireInternal(
TimeSpan duration,
RequestConditions conditions,
bool async,
- CancellationToken cancellationToken)
+ bool protocol,
+ RequestContext context = null,
+ CancellationToken cancellationToken = default)
{
EnsureClient();
// Int64 is an overflow safe cast relative to TimeSpan.MaxValue
@@ -292,9 +408,7 @@ private async Task> AcquireInternal(
$"{nameof(Uri)}: {Uri}\n" +
$"{nameof(LeaseId)}: {LeaseId}\n" +
$"{nameof(duration)}: {duration}");
-
DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(BlobLeaseClient)}.{nameof(Acquire)}");
-
try
{
scope.Start();
@@ -307,37 +421,53 @@ private async Task> AcquireInternal(
Response response;
if (BlobClient != null)
{
- ResponseWithHeaders blobClientResponse;
-
- if (async)
+ ResponseWithHeaders lease;
+ // TODO: We could collapse these separate cases if DPG
+ // and HLC generated code threw exceptions with the
+ // same information in them. See
+ // https://github.com/Azure/azure-sdk-for-net/issues/27614
+ if (protocol)
{
- blobClientResponse = await BlobClient.BlobRestClient.AcquireLeaseAsync(
- duration: serviceDuration,
- proposedLeaseId: LeaseId,
- ifModifiedSince: conditions?.IfModifiedSince,
- ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
- ifMatch: conditions?.IfMatch?.ToString(),
- ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
- ifTags: tagCondition,
- cancellationToken: cancellationToken)
- .ConfigureAwait(false);
+ Response raw = async ?
+ await BlobClient.BlobRestClient.AcquireLeaseAsync(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ ifTags: tagCondition,
+ requestConditions: conditions,
+ context: context)
+ .ConfigureAwait(false) :
+ BlobClient.BlobRestClient.AcquireLease(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ ifTags: tagCondition,
+ requestConditions: conditions,
+ context: context);
+ lease = new(new BlobAcquireLeaseHeaders(raw), raw);
}
else
{
- blobClientResponse = BlobClient.BlobRestClient.AcquireLease(
- duration: serviceDuration,
- proposedLeaseId: LeaseId,
- ifModifiedSince: conditions?.IfModifiedSince,
- ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
- ifMatch: conditions?.IfMatch?.ToString(),
- ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
- ifTags: tagCondition,
- cancellationToken: cancellationToken);
+ lease = async ?
+ await BlobClient.BlobRestClient.AcquireLeaseAsync(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ ifModifiedSince: conditions?.IfModifiedSince,
+ ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
+ ifMatch: conditions?.IfMatch?.ToString(),
+ ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
+ ifTags: tagCondition,
+ cancellationToken: cancellationToken)
+ .ConfigureAwait(false) :
+ BlobClient.BlobRestClient.AcquireLease(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ ifModifiedSince: conditions?.IfModifiedSince,
+ ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
+ ifMatch: conditions?.IfMatch?.ToString(),
+ ifNoneMatch: conditions?.IfNoneMatch?.ToString(),
+ ifTags: tagCondition,
+ cancellationToken: cancellationToken);
}
-
- response = Response.FromValue(
- blobClientResponse.ToBlobLease(),
- blobClientResponse.GetRawResponse());
+ response = Response.FromValue(lease.ToBlobLease(), lease.GetRawResponse());
}
else
{
@@ -348,31 +478,41 @@ private async Task> AcquireInternal(
operationName: nameof(BlobLeaseClient.Acquire),
parameterName: nameof(conditions));
- ResponseWithHeaders containerClientResponse;
-
- if (async)
+ ResponseWithHeaders lease;
+ if (protocol)
{
- containerClientResponse = await BlobContainerClient.ContainerRestClient.AcquireLeaseAsync(
- duration: serviceDuration,
- proposedLeaseId: LeaseId,
- ifModifiedSince: conditions?.IfModifiedSince,
- ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
- cancellationToken: cancellationToken)
- .ConfigureAwait(false);
+ Response raw = async ?
+ await BlobContainerClient.ContainerRestClient.AcquireLeaseAsync(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ requestConditions: conditions,
+ context: context)
+ .ConfigureAwait(false) :
+ BlobContainerClient.ContainerRestClient.AcquireLease(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ requestConditions: conditions,
+ context: context);
+ lease = new(new ContainerAcquireLeaseHeaders(raw), raw);
}
else
{
- containerClientResponse = BlobContainerClient.ContainerRestClient.AcquireLease(
- duration: serviceDuration,
- proposedLeaseId: LeaseId,
- ifModifiedSince: conditions?.IfModifiedSince,
- ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
- cancellationToken: cancellationToken);
+ lease = async ?
+ await BlobContainerClient.ContainerRestClient.AcquireLeaseAsync(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ ifModifiedSince: conditions?.IfModifiedSince,
+ ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
+ cancellationToken: cancellationToken)
+ .ConfigureAwait(false) :
+ BlobContainerClient.ContainerRestClient.AcquireLease(
+ duration: serviceDuration,
+ proposedLeaseId: LeaseId,
+ ifModifiedSince: conditions?.IfModifiedSince,
+ ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
+ cancellationToken: cancellationToken);
}
-
- response = Response.FromValue(
- containerClientResponse.ToBlobLease(),
- containerClientResponse.GetRawResponse());
+ response = Response.FromValue(lease.ToBlobLease(), lease.GetRawResponse());
}
LeaseId = response.Value.LeaseId;
return response;
diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs
index 9490264c8d873..b714957c985c7 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs
+++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs
@@ -11,6 +11,7 @@
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
+using Azure;
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.Storage.Blobs.Models;
@@ -305,6 +306,125 @@ public ResponseWithHeaders GetProperties(string snapsh
}
}
+ internal HttpMessage CreateGetPropertiesRequest(string snapshot, string versionId, int? timeout, string leaseId, string encryptionKey, string encryptionKeySha256, EncryptionAlgorithmTypeInternal? encryptionAlgorithm, string ifTags, RequestConditions requestConditions, RequestContext context)
+ {
+ var message = _pipeline.CreateMessage(context, ResponseClassifier200);
+ var request = message.Request;
+ request.Method = RequestMethod.Head;
+ var uri = new RawRequestUriBuilder();
+ uri.AppendRaw(_url, false);
+ if (snapshot != null)
+ {
+ uri.AppendQuery("snapshot", snapshot, true);
+ }
+ if (versionId != null)
+ {
+ uri.AppendQuery("versionid", versionId, true);
+ }
+ if (timeout != null)
+ {
+ uri.AppendQuery("timeout", timeout.Value, true);
+ }
+ request.Uri = uri;
+ if (leaseId != null)
+ {
+ request.Headers.Add("x-ms-lease-id", leaseId);
+ }
+ if (encryptionKey != null)
+ {
+ request.Headers.Add("x-ms-encryption-key", encryptionKey);
+ }
+ if (encryptionKeySha256 != null)
+ {
+ request.Headers.Add("x-ms-encryption-key-sha256", encryptionKeySha256);
+ }
+ if (encryptionAlgorithm != null)
+ {
+ request.Headers.Add("x-ms-encryption-algorithm", encryptionAlgorithm.Value.ToSerialString());
+ }
+ if (ifTags != null)
+ {
+ request.Headers.Add("x-ms-if-tags", ifTags);
+ }
+ request.Headers.Add("x-ms-version", _version);
+ request.Headers.Add("Accept", "application/xml");
+ if (requestConditions != null)
+ {
+ request.Headers.Add(requestConditions, "R");
+ }
+ return message;
+ }
+
+ /// The Get Properties operation returns all user-defined metadata, standard HTTP properties, and system properties for the blob. It does not return the content of the blob.
+ /// The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>.
+ /// The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. It's for service version 2019-10-10 and newer.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// If specified, the operation only succeeds if the resource's lease is active and matches this ID.
+ /// Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services.
+ /// The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided.
+ /// The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided.
+ /// Specify a SQL where clause on blob tags to operate only on blobs with a matching value.
+ /// The content to send as the request conditions of the request.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual async Task GetPropertiesAsync(string snapshot = null, string versionId = null, int? timeout = null, string leaseId = null, string encryptionKey = null, string encryptionKeySha256 = null, EncryptionAlgorithmTypeInternal? encryptionAlgorithm = null, string ifTags = null, RequestConditions requestConditions = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("BlobClient.GetProperties");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateGetPropertiesRequest(snapshot, versionId, timeout, leaseId, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifTags, requestConditions, context);
+ return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
+ /// The Get Properties operation returns all user-defined metadata, standard HTTP properties, and system properties for the blob. It does not return the content of the blob.
+ /// The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>.
+ /// The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. It's for service version 2019-10-10 and newer.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// If specified, the operation only succeeds if the resource's lease is active and matches this ID.
+ /// Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services.
+ /// The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided.
+ /// The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided.
+ /// Specify a SQL where clause on blob tags to operate only on blobs with a matching value.
+ /// The content to send as the request conditions of the request.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual Response GetProperties(string snapshot = null, string versionId = null, int? timeout = null, string leaseId = null, string encryptionKey = null, string encryptionKeySha256 = null, EncryptionAlgorithmTypeInternal? encryptionAlgorithm = null, string ifTags = null, RequestConditions requestConditions = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("BlobClient.GetProperties");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateGetPropertiesRequest(snapshot, versionId, timeout, leaseId, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifTags, requestConditions, context);
+ return _pipeline.ProcessMessage(message, context);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
internal HttpMessage CreateDeleteRequest(string snapshot, string versionId, int? timeout, string leaseId, DeleteSnapshotsOption? deleteSnapshots, DateTimeOffset? ifModifiedSince, DateTimeOffset? ifUnmodifiedSince, string ifMatch, string ifNoneMatch, string ifTags, BlobDeleteType? blobDeleteType)
{
var message = _pipeline.CreateMessage();
@@ -1043,6 +1163,103 @@ public ResponseWithHeaders AcquireLease(int? timeout =
}
}
+ internal HttpMessage CreateAcquireLeaseRequest(int? timeout, long? duration, string proposedLeaseId, string ifTags, RequestConditions requestConditions, RequestContext context)
+ {
+ var message = _pipeline.CreateMessage(context, ResponseClassifier201);
+ var request = message.Request;
+ request.Method = RequestMethod.Put;
+ var uri = new RawRequestUriBuilder();
+ uri.AppendRaw(_url, false);
+ uri.AppendQuery("comp", "lease", true);
+ if (timeout != null)
+ {
+ uri.AppendQuery("timeout", timeout.Value, true);
+ }
+ request.Uri = uri;
+ request.Headers.Add("x-ms-lease-action", "acquire");
+ if (duration != null)
+ {
+ request.Headers.Add("x-ms-lease-duration", duration.Value);
+ }
+ if (proposedLeaseId != null)
+ {
+ request.Headers.Add("x-ms-proposed-lease-id", proposedLeaseId);
+ }
+ if (ifTags != null)
+ {
+ request.Headers.Add("x-ms-if-tags", ifTags);
+ }
+ request.Headers.Add("x-ms-version", _version);
+ request.Headers.Add("Accept", "application/xml");
+ if (requestConditions != null)
+ {
+ request.Headers.Add(requestConditions, "R");
+ }
+ return message;
+ }
+
+ /// [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change.
+ /// Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats.
+ /// Specify a SQL where clause on blob tags to operate only on blobs with a matching value.
+ /// The content to send as the request conditions of the request.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual async Task AcquireLeaseAsync(int? timeout = null, long? duration = null, string proposedLeaseId = null, string ifTags = null, RequestConditions requestConditions = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("BlobClient.AcquireLease");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateAcquireLeaseRequest(timeout, duration, proposedLeaseId, ifTags, requestConditions, context);
+ return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
+ /// [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change.
+ /// Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats.
+ /// Specify a SQL where clause on blob tags to operate only on blobs with a matching value.
+ /// The content to send as the request conditions of the request.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual Response AcquireLease(int? timeout = null, long? duration = null, string proposedLeaseId = null, string ifTags = null, RequestConditions requestConditions = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("BlobClient.AcquireLease");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateAcquireLeaseRequest(timeout, duration, proposedLeaseId, ifTags, requestConditions, context);
+ return _pipeline.ProcessMessage(message, context);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
internal HttpMessage CreateReleaseLeaseRequest(string leaseId, int? timeout, DateTimeOffset? ifModifiedSince, DateTimeOffset? ifUnmodifiedSince, string ifMatch, string ifNoneMatch, string ifTags)
{
var message = _pipeline.CreateMessage();
@@ -2395,5 +2612,10 @@ public ResponseWithHeaders SetTags(int? timeout = null, stri
throw ClientDiagnostics.CreateRequestFailedException(message.Response);
}
}
+
+ private static ResponseClassifier _responseClassifier200;
+ private static ResponseClassifier ResponseClassifier200 => _responseClassifier200 ??= new StatusCodeClassifier(stackalloc ushort[] { 200 });
+ private static ResponseClassifier _responseClassifier201;
+ private static ResponseClassifier ResponseClassifier201 => _responseClassifier201 ??= new StatusCodeClassifier(stackalloc ushort[] { 201 });
}
}
diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs
index 25d5476469caa..5d90548da5373 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs
+++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs
@@ -11,6 +11,7 @@
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
+using Azure;
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.Storage.Blobs.Models;
@@ -174,6 +175,84 @@ public ResponseWithHeaders GetProperties(int? tim
}
}
+ internal HttpMessage CreateGetPropertiesRequest(int? timeout, string leaseId, RequestContext context)
+ {
+ var message = _pipeline.CreateMessage(context, ResponseClassifier200);
+ var request = message.Request;
+ request.Method = RequestMethod.Get;
+ var uri = new RawRequestUriBuilder();
+ uri.AppendRaw(_url, false);
+ uri.AppendQuery("restype", "container", true);
+ if (timeout != null)
+ {
+ uri.AppendQuery("timeout", timeout.Value, true);
+ }
+ request.Uri = uri;
+ if (leaseId != null)
+ {
+ request.Headers.Add("x-ms-lease-id", leaseId);
+ }
+ request.Headers.Add("x-ms-version", _version);
+ request.Headers.Add("Accept", "application/xml");
+ return message;
+ }
+
+ /// returns all user-defined metadata and system properties for the specified container. The data returned does not include the container's list of blobs.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// If specified, the operation only succeeds if the resource's lease is active and matches this ID.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual async Task GetPropertiesAsync(int? timeout = null, string leaseId = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("ContainerClient.GetProperties");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateGetPropertiesRequest(timeout, leaseId, context);
+ return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
+ /// returns all user-defined metadata and system properties for the specified container. The data returned does not include the container's list of blobs.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// If specified, the operation only succeeds if the resource's lease is active and matches this ID.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual Response GetProperties(int? timeout = null, string leaseId = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("ContainerClient.GetProperties");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateGetPropertiesRequest(timeout, leaseId, context);
+ return _pipeline.ProcessMessage(message, context);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
internal HttpMessage CreateDeleteRequest(int? timeout, string leaseId, DateTimeOffset? ifModifiedSince, DateTimeOffset? ifUnmodifiedSince)
{
var message = _pipeline.CreateMessage();
@@ -883,6 +962,104 @@ public ResponseWithHeaders AcquireLease(int? timeo
}
}
+ internal HttpMessage CreateAcquireLeaseRequest(int? timeout, long? duration, string proposedLeaseId, RequestConditions requestConditions, RequestContext context)
+ {
+ var message = _pipeline.CreateMessage(context, ResponseClassifier201);
+ var request = message.Request;
+ request.Method = RequestMethod.Put;
+ var uri = new RawRequestUriBuilder();
+ uri.AppendRaw(_url, false);
+ uri.AppendQuery("comp", "lease", true);
+ uri.AppendQuery("restype", "container", true);
+ if (timeout != null)
+ {
+ uri.AppendQuery("timeout", timeout.Value, true);
+ }
+ request.Uri = uri;
+ request.Headers.Add("x-ms-lease-action", "acquire");
+ if (duration != null)
+ {
+ request.Headers.Add("x-ms-lease-duration", duration.Value);
+ }
+ if (proposedLeaseId != null)
+ {
+ request.Headers.Add("x-ms-proposed-lease-id", proposedLeaseId);
+ }
+ request.Headers.Add("x-ms-version", _version);
+ request.Headers.Add("Accept", "application/xml");
+ if (requestConditions != null)
+ {
+ request.Headers.Add(requestConditions, "R");
+ }
+ return message;
+ }
+
+ /// [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change.
+ /// Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats.
+ /// The content to send as the request conditions of the request.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual async Task AcquireLeaseAsync(int? timeout = null, long? duration = null, string proposedLeaseId = null, RequestConditions requestConditions = null, RequestContext context = null)
+ {
+ Argument.AssertNull(requestConditions.IfMatch, nameof(requestConditions), "Service does not support the If-Match header for this operation.");
+ Argument.AssertNull(requestConditions.IfNoneMatch, nameof(requestConditions), "Service does not support the If-None-Match header for this operation.");
+
+ using var scope = ClientDiagnostics.CreateScope("ContainerClient.AcquireLease");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateAcquireLeaseRequest(timeout, duration, proposedLeaseId, requestConditions, context);
+ return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
+ /// [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change.
+ /// Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats.
+ /// The content to send as the request conditions of the request.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual Response AcquireLease(int? timeout = null, long? duration = null, string proposedLeaseId = null, RequestConditions requestConditions = null, RequestContext context = null)
+ {
+ Argument.AssertNull(requestConditions.IfMatch, nameof(requestConditions), "Service does not support the If-Match header for this operation.");
+ Argument.AssertNull(requestConditions.IfNoneMatch, nameof(requestConditions), "Service does not support the If-None-Match header for this operation.");
+
+ using var scope = ClientDiagnostics.CreateScope("ContainerClient.AcquireLease");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateAcquireLeaseRequest(timeout, duration, proposedLeaseId, requestConditions, context);
+ return _pipeline.ProcessMessage(message, context);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
internal HttpMessage CreateReleaseLeaseRequest(string leaseId, int? timeout, DateTimeOffset? ifModifiedSince, DateTimeOffset? ifUnmodifiedSince)
{
var message = _pipeline.CreateMessage();
@@ -1574,5 +1751,10 @@ public ResponseWithHeaders _responseClassifier200 ??= new StatusCodeClassifier(stackalloc ushort[] { 200 });
+ private static ResponseClassifier _responseClassifier201;
+ private static ResponseClassifier ResponseClassifier201 => _responseClassifier201 ??= new StatusCodeClassifier(stackalloc ushort[] { 201 });
}
}
diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs
index c343350afe15d..dbb5835afa63f 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs
+++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs
@@ -11,6 +11,7 @@
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
+using Azure;
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.Storage.Blobs.Models;
@@ -182,6 +183,158 @@ public ResponseWithHeaders G
}
}
+ internal HttpMessage CreateGetPropertiesRequest(int? timeout, RequestContext context)
+ {
+ var message = _pipeline.CreateMessage(context, ResponseClassifier200);
+ var request = message.Request;
+ request.Method = RequestMethod.Get;
+ var uri = new RawRequestUriBuilder();
+ uri.AppendRaw(_url, false);
+ uri.AppendPath("/", false);
+ uri.AppendQuery("restype", "service", true);
+ uri.AppendQuery("comp", "properties", true);
+ if (timeout != null)
+ {
+ uri.AppendQuery("timeout", timeout.Value, true);
+ }
+ request.Uri = uri;
+ request.Headers.Add("x-ms-version", _version);
+ request.Headers.Add("Accept", "application/xml");
+ return message;
+ }
+
+ /// gets the properties of a storage account's Blob service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Body:
+ /// {
+ /// Logging: {
+ /// Version: string,
+ /// Delete: boolean,
+ /// Read: boolean,
+ /// Write: boolean,
+ /// RetentionPolicy: {
+ /// Enabled: boolean,
+ /// Days: number,
+ /// AllowPermanentDelete: boolean
+ /// }
+ /// },
+ /// HourMetrics: {
+ /// Version: string,
+ /// Enabled: boolean,
+ /// IncludeAPIs: boolean,
+ /// RetentionPolicy: RetentionPolicy
+ /// },
+ /// MinuteMetrics: Metrics,
+ /// Cors: [
+ /// {
+ /// AllowedOrigins: string,
+ /// AllowedMethods: string,
+ /// AllowedHeaders: string,
+ /// ExposedHeaders: string,
+ /// MaxAgeInSeconds: number
+ /// }
+ /// ],
+ /// DefaultServiceVersion: string,
+ /// DeleteRetentionPolicy: RetentionPolicy,
+ /// StaticWebsite: {
+ /// Enabled: boolean,
+ /// IndexDocument: string,
+ /// ErrorDocument404Path: string,
+ /// DefaultIndexDocumentPath: string
+ /// }
+ /// }
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual async Task GetPropertiesAsync(int? timeout = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("ServiceClient.GetProperties");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateGetPropertiesRequest(timeout, context);
+ return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
+ /// gets the properties of a storage account's Blob service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules.
+ /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>.
+ /// The request context, which can override default behaviors on the request on a per-call basis.
+ ///
+ /// Schema for Response Body:
+ /// {
+ /// Logging: {
+ /// Version: string,
+ /// Delete: boolean,
+ /// Read: boolean,
+ /// Write: boolean,
+ /// RetentionPolicy: {
+ /// Enabled: boolean,
+ /// Days: number,
+ /// AllowPermanentDelete: boolean
+ /// }
+ /// },
+ /// HourMetrics: {
+ /// Version: string,
+ /// Enabled: boolean,
+ /// IncludeAPIs: boolean,
+ /// RetentionPolicy: RetentionPolicy
+ /// },
+ /// MinuteMetrics: Metrics,
+ /// Cors: [
+ /// {
+ /// AllowedOrigins: string,
+ /// AllowedMethods: string,
+ /// AllowedHeaders: string,
+ /// ExposedHeaders: string,
+ /// MaxAgeInSeconds: number
+ /// }
+ /// ],
+ /// DefaultServiceVersion: string,
+ /// DeleteRetentionPolicy: RetentionPolicy,
+ /// StaticWebsite: {
+ /// Enabled: boolean,
+ /// IndexDocument: string,
+ /// ErrorDocument404Path: string,
+ /// DefaultIndexDocumentPath: string
+ /// }
+ /// }
+ ///
+ /// Schema for Response Error:
+ /// {
+ /// Message: string
+ /// }
+ ///
+ ///
+ ///
+ public virtual Response GetProperties(int? timeout = null, RequestContext context = null)
+ {
+ using var scope = ClientDiagnostics.CreateScope("ServiceClient.GetProperties");
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateGetPropertiesRequest(timeout, context);
+ return _pipeline.ProcessMessage(message, context);
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
internal HttpMessage CreateGetStatisticsRequest(int? timeout)
{
var message = _pipeline.CreateMessage();
@@ -741,5 +894,8 @@ public ResponseWithHeaders _responseClassifier200 ??= new StatusCodeClassifier(stackalloc ushort[] { 200 });
}
}
diff --git a/sdk/storage/Azure.Storage.Blobs/src/autorest.md b/sdk/storage/Azure.Storage.Blobs/src/autorest.md
index c95953572823c..1302d1de682cf 100644
--- a/sdk/storage/Azure.Storage.Blobs/src/autorest.md
+++ b/sdk/storage/Azure.Storage.Blobs/src/autorest.md
@@ -341,4 +341,14 @@ directive:
transform: >
$.BlobItemInternal.properties["OrMetadata"] = $.BlobItemInternal.properties["ObjectReplicationMetadata"];
delete $.BlobItemInternal.properties["ObjectReplicationMetadata"];
-```
\ No newline at end of file
+```
+
+### Generate DPG methods
+(note that these are just the latter half of OperationIds today but will
+possibly change to full OperationIds in the future and this will break.
+See https://github.com/Azure/autorest.csharp/issues/2078)
+```yaml
+protocol-method-list:
+ - GetProperties
+ - AcquireLease
+```
diff --git a/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj b/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj
index 1a2b0bed7de94..4e00ef2b11788 100644
--- a/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj
+++ b/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj
@@ -20,7 +20,12 @@
true
+
+
+
+
diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/StorageExceptionExtensions.cs b/sdk/storage/Azure.Storage.Common/src/Shared/StorageExceptionExtensions.cs
index 5a6f254d1d970..d693f6ff15838 100644
--- a/sdk/storage/Azure.Storage.Common/src/Shared/StorageExceptionExtensions.cs
+++ b/sdk/storage/Azure.Storage.Common/src/Shared/StorageExceptionExtensions.cs
@@ -20,7 +20,7 @@ internal static class StorageExceptionExtensions
/// The response.
/// An optional error code.
/// The response's error code.
- public static string GetErrorCode(this Response response, string errorCode)
+ public static string GetErrorCode(this Response response, string errorCode = null)
{
if (string.IsNullOrEmpty(errorCode))
{
diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/BlobReceiptManager.cs b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/BlobReceiptManager.cs
index d5d199a2425d8..94477d829a71b 100644
--- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/BlobReceiptManager.cs
+++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/BlobReceiptManager.cs
@@ -9,6 +9,7 @@
using System.Threading;
using System.Threading.Tasks;
using Azure;
+using Azure.Core;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
@@ -122,27 +123,36 @@ await blob.UploadAsync(
public async Task TryAcquireLeaseAsync(BlockBlobClient blob, CancellationToken cancellationToken)
{
- try
- {
- BlobLease lease = await blob.GetBlobLeaseClient().AcquireAsync(LeasePeriod, cancellationToken: cancellationToken).ConfigureAwait(false);
- return lease.LeaseId;
- }
- catch (RequestFailedException exception)
+ RequestContext context =
+ new RequestContext()
+ {
+ ErrorOptions = ErrorOptions.NoThrow,
+ CancellationToken = cancellationToken
+ }
+ .AddClassifier(409, BlobErrorCode.LeaseAlreadyPresent.ToString(), false)
+ .AddClassifier(404, BlobErrorCode.BlobNotFound.ToString(), false)
+ .AddClassifier(404, BlobErrorCode.ContainerNotFound.ToString(), false);
+ Response response =
+ await blob.GetBlobLeaseClient()
+ .AcquireAsync(LeasePeriod, conditions: null, context)
+ .ConfigureAwait(false);
+
+ // If the response was any error other than a 409
+ // LeaseAlreadyPresent, a 404 ContainerNotFound, or a 404
+ // BlobNotFound we will throw
+ Response raw = response.GetRawResponse();
+ if (raw.IsError)
{
- if (exception.IsConflictLeaseAlreadyPresent())
- {
- return null;
- }
- else if (exception.IsNotFoundBlobOrContainerNotFound())
- {
- // If someone deleted the receipt, there's no lease to acquire.
- return null;
- }
- else
- {
- throw;
- }
+ throw new RequestFailedException(raw);
+ // Note: this is currently not working correctly because of
+ // https://github.com/Azure/azure-sdk-for-net/issues/27614
+ // and will throw an exception without the ErrorCode or other
+ // important information populated
}
+
+ // Return the lease if we successfully acquired it or null if
+ // someone else holds the lease or the receipt was already deleted
+ return raw.Status == 201 ? response.Value.LeaseId : null;
}
public async Task MarkCompletedAsync(BlockBlobClient blob, string leaseId,
diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.csproj b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.csproj
index 97959411feff8..e36d129e7fbd0 100644
--- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.csproj
+++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.csproj
@@ -12,13 +12,20 @@
+
+
+
+
+
+