From 0f3f8066bd46ecef637b839d88711d600f17874a Mon Sep 17 00:00:00 2001
From: m-nash <64171366+m-nash@users.noreply.github.com>
Date: Mon, 22 Mar 2021 10:16:12 -0700
Subject: [PATCH 01/15] WIP
---
.../src/ArmResponse.cs | 46 ---
.../src/GenericResourceOperations.cs | 14 +-
.../src/IDeletableResource.cs | 4 +-
.../src/{ => Operation}/ArmOperation.cs | 40 +-
.../src/Operation/ArmOperationHelpers.cs | 369 ++++++++++++++++++
.../PhArmOperation.cs | 1 -
.../src/Operation/ValueArmOperation.cs | 48 +++
.../VoidArmOperation.cs} | 21 +-
.../src/ResourceGroupOperations.cs | 16 +-
.../src/Response/ArmResponse.cs | 60 +++
.../{Adapters => Response}/PhArmResponse.cs | 0
.../src/Response/ValueArmResponse.cs | 24 ++
.../src/Response/VoidArmResponse.cs | 54 +++
.../src/UpdateResourceGroupOperation.cs | 20 +
.../tests/Unit/ArmResponseTests.cs | 3 +-
.../tests/Unit/ResourceTypeFilterTests.cs | 4 +-
16 files changed, 629 insertions(+), 95 deletions(-)
delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs
rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{ => Operation}/ArmOperation.cs (75%)
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs
rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{Placeholder => Operation}/PhArmOperation.cs (99%)
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{ArmVoidOperation.cs => Operation/VoidArmOperation.cs} (85%)
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs
rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{Adapters => Response}/PhArmResponse.cs (100%)
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs
deleted file mode 100644
index c9f4e005822d..000000000000
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-using System;
-
-namespace Azure.ResourceManager.Core
-{
- ///
- /// A class representing a response object from azure resource manager service.
- ///
- public sealed class ArmResponse : ArmResponse
- {
- private readonly Response _response;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The azure response object to wrap.
- /// If is null.
- public ArmResponse(Response response)
- {
- if (response is null)
- throw new ArgumentNullException(nameof(response));
-
- _response = response;
- }
-
- ///
- public override Response Value => _response;
-
- ///
- public override Response GetRawResponse()
- {
- return _response;
- }
- }
-
- ///
- /// A class representing a response object from azure resource manager service.
- ///
- /// The operations object return by the api call.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Allowed when we have a generic version of the same type")]
- public abstract class ArmResponse : Response
- {
- }
-}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs
index 733cab70e87f..bf2381da4074 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs
@@ -41,9 +41,9 @@ internal GenericResourceOperations(ResourceOperationsBase operations, ResourceId
///
/// A token allowing immediate cancellation of any blocking call performed during the deletion.
/// The status of the delete operation.
- public ArmResponse Delete(CancellationToken cancellationToken = default)
+ public ArmResponse Delete(CancellationToken cancellationToken = default)
{
- return new ArmResponse(Operations.StartDeleteById(Id, _apiVersion, cancellationToken).WaitForCompletion(cancellationToken));
+ return ArmResponse.FromResponse(Operations.StartDeleteById(Id, _apiVersion, cancellationToken).WaitForCompletion(cancellationToken));
}
///
@@ -51,11 +51,11 @@ public ArmResponse Delete(CancellationToken cancellationToken = defaul
///
/// A token allowing immediate cancellation of any blocking call performed during the deletion.
/// A that on completion returns the status of the delete operation.
- public async Task> DeleteAsync(CancellationToken cancellationToken = default)
+ public async Task DeleteAsync(CancellationToken cancellationToken = default)
{
var operation = await Operations.StartDeleteByIdAsync(Id, _apiVersion, cancellationToken).ConfigureAwait(false);
var result = await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false);
- return new ArmResponse(result);
+ return ArmResponse.FromResponse(result);
}
///
@@ -69,7 +69,7 @@ public async Task> DeleteAsync(CancellationToken cancellat
///
public ArmOperation StartDelete(CancellationToken cancellationToken = default)
{
- return new ArmVoidOperation(Operations.StartDeleteById(Id, _apiVersion, cancellationToken));
+ return new VoidArmOperation(Operations.StartDeleteById(Id, _apiVersion, cancellationToken));
}
///
@@ -86,15 +86,13 @@ public ArmOperation StartDelete(CancellationToken cancellationToken =
public async Task> StartDeleteAsync(CancellationToken cancellationToken = default)
{
var operation = await Operations.StartDeleteByIdAsync(Id, _apiVersion, cancellationToken).ConfigureAwait(false);
- return new ArmVoidOperation(operation);
+ return new VoidArmOperation(operation);
}
///
public ArmResponse AddTag(string key, string value, CancellationToken cancellationToken = default)
{
GenericResource resource = GetResource();
-
- // Potential optimization on tags set, remove NOOP to bypass the call.
resource.Data.Tags[key] = value;
return new PhArmResponse(
Operations.StartUpdateById(Id, _apiVersion, resource.Data, cancellationToken).WaitForCompletionAsync(cancellationToken).EnsureCompleted(),
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs
index 782049e856f9..fd799644ae3f 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs
@@ -16,14 +16,14 @@ public interface IDeletableResource
///
/// A token allowing immediate cancellation of any blocking call performed during the deletion.
/// The status of the delete operation.
- ArmResponse Delete(CancellationToken cancellationToken = default);
+ ArmResponse Delete(CancellationToken cancellationToken = default);
///
/// Delete the resource.
///
/// A token allowing immediate cancellation of any blocking call performed during the deletion.
/// A that on completion returns the status of the delete operation.
- Task> DeleteAsync(CancellationToken cancellationToken = default);
+ Task DeleteAsync(CancellationToken cancellationToken = default);
///
/// Delete the resource.
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
similarity index 75%
rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmOperation.cs
rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
index dcd49e489a6c..35d166888f62 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
@@ -8,11 +8,20 @@
namespace Azure.ResourceManager.Core
{
+ ///
+ /// Abstract class for long-running or synchronous applications.
+ ///
+ public abstract class ArmOperation : ArmOperation, IOperationSource
+ {
+ }
+
///
/// Abstract class for long-running or synchronous applications.
///
/// The to return representing the result of the ArmOperation.
- public abstract class ArmOperation : Operation
+#pragma warning disable SA1402 // File may only contain a single type
+ public abstract class ArmOperation : Operation, IOperationSource
+#pragma warning restore SA1402 // File may only contain a single type
{
///
/// Initializes a new instance of the class for mocking.
@@ -22,24 +31,26 @@ protected ArmOperation()
}
///
- /// Initializes a new instance of the class.
+ /// Gets or sets the SyncValue
///
- /// The representing the result of the ArmOperation.
- protected ArmOperation(TOperations syncValue)
- {
- CompletedSynchronously = syncValue != null;
- SyncValue = syncValue;
- }
+ protected TOperations SyncValue { get; set; }
///
- /// Gets a value indicating whether or not the operation completed synchronously.
+ /// Gets or sets whether or not this is an LRO
///
- protected bool CompletedSynchronously { get; }
+ protected bool IsLongRunningOperation { get; set; }
- ///
- /// Gets the representing the result of the ArmOperation.
- ///
- protected TOperations SyncValue { get; }
+ ///
+ public TOperations CreateResult(Response response, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
///
/// Waits for the completion of the long running operations.
@@ -65,7 +76,6 @@ public ArmResponse WaitForCompletion(CancellationToken cancellation
///
public ArmResponse WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default)
{
- var polling = TimeSpan.FromSeconds(pollingInterval);
while (true)
{
UpdateStatus(cancellationToken);
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs
new file mode 100644
index 000000000000..96ffbdbb9d99
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs
@@ -0,0 +1,369 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System;
+using System.Linq;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Core;
+using Azure.Core.Pipeline;
+
+namespace Azure.ResourceManager.Core
+{
+ ///
+ /// This implements the ARM scenarios for LROs. It is highly recommended to read the ARM spec prior to modifying this code:
+ /// https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/Addendum.md#asynchronous-operations
+ /// Other reference documents include:
+ /// https://github.com/Azure/autorest/blob/master/docs/extensions/readme.md#x-ms-long-running-operation
+ /// https://github.com/Azure/adx-documentation-pr/blob/master/sdks/LRO/LRO_AzureSDK.md
+ ///
+ /// The final result of the LRO.
+ internal class ArmOperationHelpers
+ {
+ public static TimeSpan DefaultPollingInterval { get; } = TimeSpan.FromSeconds(1);
+
+ private static readonly string[] s_failureStates = { "failed", "canceled" };
+ private static readonly string[] s_terminalStates = { "succeeded", "failed", "canceled" };
+
+ private readonly HttpPipeline _pipeline;
+ private readonly ClientDiagnostics _clientDiagnostics;
+ private readonly string _scopeName;
+ private readonly RequestMethod _requestMethod;
+ private readonly Uri _originalUri;
+ private readonly OperationFinalStateVia _finalStateVia;
+ private HeaderFrom _headerFrom;
+ private string _pollUri = default!;
+ private bool _originalHasLocation;
+ private string? _lastKnownLocation;
+
+ private readonly IOperationSource _source;
+ private Response _rawResponse;
+ private T _value = default!;
+ private bool _hasValue;
+ private bool _hasCompleted;
+ private bool _shouldPoll;
+
+ public ArmOperationHelpers(
+ IOperationSource source,
+ ClientDiagnostics clientDiagnostics,
+ HttpPipeline pipeline,
+ Request originalRequest,
+ Response originalResponse,
+ OperationFinalStateVia finalStateVia,
+ string scopeName)
+ {
+ _source = source;
+ _rawResponse = originalResponse;
+ _requestMethod = originalRequest.Method;
+ _originalUri = originalRequest.Uri.ToUri();
+ _finalStateVia = finalStateVia;
+ InitializeScenarioInfo();
+
+ _pipeline = pipeline;
+ _clientDiagnostics = clientDiagnostics;
+ _scopeName = scopeName;
+ // When the original response has no headers, we do not start polling immediately.
+ _shouldPoll = _headerFrom != HeaderFrom.None;
+ }
+
+ public Response GetRawResponse() => _rawResponse;
+
+ public ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default)
+ {
+ return WaitForCompletionAsync(DefaultPollingInterval, cancellationToken);
+ }
+
+ public async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken)
+ {
+ while (true)
+ {
+ await UpdateStatusAsync(cancellationToken).ConfigureAwait(false);
+ if (HasCompleted)
+ {
+ return Response.FromValue(Value, GetRawResponse());
+ }
+
+ await Task.Delay(pollingInterval, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async ValueTask UpdateStatusAsync(bool async, CancellationToken cancellationToken)
+ {
+ if (_hasCompleted)
+ {
+ return GetRawResponse();
+ }
+
+ if (_shouldPoll)
+ {
+ UpdatePollUri();
+ _rawResponse = async
+ ? await GetResponseAsync(_pollUri, cancellationToken).ConfigureAwait(false)
+ : GetResponse(_pollUri, cancellationToken);
+ }
+
+ _shouldPoll = true;
+ _hasCompleted = IsTerminalState(out string state);
+ if (_hasCompleted)
+ {
+ Response finalResponse = GetRawResponse();
+ if (s_failureStates.Contains(state))
+ {
+ throw _clientDiagnostics.CreateRequestFailedException(finalResponse);
+ }
+
+ string? finalUri = GetFinalUri();
+ if (finalUri != null)
+ {
+ finalResponse = async
+ ? await GetResponseAsync(finalUri, cancellationToken).ConfigureAwait(false)
+ : GetResponse(finalUri, cancellationToken);
+ }
+
+ switch (finalResponse.Status)
+ {
+ case 200:
+ case 201 when _requestMethod == RequestMethod.Put:
+ case 204 when !(_requestMethod == RequestMethod.Put || _requestMethod == RequestMethod.Patch):
+ {
+ _value = async
+ ? await _source.CreateResultAsync(finalResponse, cancellationToken).ConfigureAwait(false)
+ : _source.CreateResult(finalResponse, cancellationToken);
+ _rawResponse = finalResponse;
+ _hasValue = true;
+ break;
+ }
+ default:
+ throw _clientDiagnostics.CreateRequestFailedException(finalResponse);
+ }
+ }
+
+ return GetRawResponse();
+ }
+
+ public async ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => await UpdateStatusAsync(async: true, cancellationToken).ConfigureAwait(false);
+
+ public Response UpdateStatus(CancellationToken cancellationToken = default) => UpdateStatusAsync(async: false, cancellationToken).EnsureCompleted();
+
+#pragma warning disable CA1822
+ //TODO: This is currently unused.
+ public string Id => throw new NotImplementedException();
+#pragma warning restore CA1822
+
+ public T Value
+ {
+ get
+ {
+ if (!HasValue)
+ {
+ throw new InvalidOperationException("The operation has not completed yet.");
+ }
+
+ return _value;
+ }
+ }
+
+ public bool HasCompleted => _hasCompleted;
+ public bool HasValue => _hasValue;
+
+ private HttpMessage CreateRequest(string link)
+ {
+ HttpMessage message = _pipeline.CreateMessage();
+ Request request = message.Request;
+ request.Method = RequestMethod.Get;
+
+ if (Uri.TryCreate(link, UriKind.Absolute, out var nextLink) && nextLink.Scheme != "file")
+ {
+ request.Uri.Reset(nextLink);
+ }
+ else
+ {
+ request.Uri.Reset(new Uri(_originalUri, link));
+ }
+
+ return message;
+ }
+
+ private async ValueTask GetResponseAsync(string link, CancellationToken cancellationToken = default)
+ {
+ if (link == null)
+ {
+ throw new ArgumentNullException(nameof(link));
+ }
+
+ using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName);
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateRequest(link);
+ await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);
+ return message.Response;
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
+ private Response GetResponse(string link, CancellationToken cancellationToken = default)
+ {
+ if (link == null)
+ {
+ throw new ArgumentNullException(nameof(link));
+ }
+
+ using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName);
+ scope.Start();
+ try
+ {
+ using HttpMessage message = CreateRequest(link);
+ _pipeline.Send(message, cancellationToken);
+ return message.Response;
+ }
+ catch (Exception e)
+ {
+ scope.Failed(e);
+ throw;
+ }
+ }
+
+ private bool IsTerminalState(out string state)
+ {
+ Response response = GetRawResponse();
+ state = string.Empty;
+ if (_headerFrom == HeaderFrom.Location)
+ {
+ return response.Status != 202;
+ }
+
+ if (response.Status >= 200 && response.Status <= 204)
+ {
+ if (response.ContentStream?.Length > 0)
+ {
+ try
+ {
+ using JsonDocument document = JsonDocument.Parse(response.ContentStream);
+ foreach (JsonProperty property in document.RootElement.EnumerateObject())
+ {
+ if ((_headerFrom == HeaderFrom.OperationLocation ||
+ _headerFrom == HeaderFrom.AzureAsyncOperation) &&
+ property.NameEquals("status"))
+ {
+ state = property.Value.GetString().ToLowerInvariant();
+ return s_terminalStates.Contains(state);
+ }
+
+ if (_headerFrom == HeaderFrom.None && property.NameEquals("properties"))
+ {
+ foreach (JsonProperty innerProperty in property.Value.EnumerateObject())
+ {
+ if (innerProperty.NameEquals("provisioningState"))
+ {
+ state = innerProperty.Value.GetString().ToLowerInvariant();
+ return s_terminalStates.Contains(state);
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ // It is required to reset the position of the content after reading as this response may be used for deserialization.
+ response.ContentStream.Position = 0;
+ }
+ }
+
+ // If provisioningState was not found, it defaults to Succeeded.
+ if (_headerFrom == HeaderFrom.None)
+ {
+ return true;
+ }
+ }
+
+ throw _clientDiagnostics.CreateRequestFailedException(response);
+ }
+
+ private enum HeaderFrom
+ {
+ None,
+ OperationLocation,
+ AzureAsyncOperation,
+ Location
+ }
+
+ private void InitializeScenarioInfo()
+ {
+ _originalHasLocation = _rawResponse.Headers.Contains("Location");
+
+ if (_rawResponse.Headers.Contains("Operation-Location"))
+ {
+ _headerFrom = HeaderFrom.OperationLocation;
+ return;
+ }
+
+ if (_rawResponse.Headers.Contains("Azure-AsyncOperation"))
+ {
+ _headerFrom = HeaderFrom.AzureAsyncOperation;
+ return;
+ }
+
+ if (_originalHasLocation)
+ {
+ _headerFrom = HeaderFrom.Location;
+ return;
+ }
+
+ _pollUri = _originalUri.AbsoluteUri;
+ _headerFrom = HeaderFrom.None;
+ }
+
+ private void UpdatePollUri()
+ {
+ var hasLocation = _rawResponse.Headers.TryGetValue("Location", out string? location);
+ if (hasLocation)
+ {
+ _lastKnownLocation = location;
+ }
+
+ switch (_headerFrom)
+ {
+ case HeaderFrom.OperationLocation when _rawResponse.Headers.TryGetValue("Operation-Location", out string? operationLocation):
+ _pollUri = operationLocation;
+ return;
+ case HeaderFrom.AzureAsyncOperation when _rawResponse.Headers.TryGetValue("Azure-AsyncOperation", out string? azureAsyncOperation):
+ _pollUri = azureAsyncOperation;
+ return;
+ case HeaderFrom.Location when hasLocation:
+ _pollUri = location!;
+ return;
+ }
+ }
+
+ private string? GetFinalUri()
+ {
+ if (_headerFrom == HeaderFrom.OperationLocation || _headerFrom == HeaderFrom.AzureAsyncOperation)
+ {
+ if (_requestMethod == RequestMethod.Delete)
+ {
+ return null;
+ }
+
+ if (_requestMethod == RequestMethod.Put || (_originalHasLocation && _finalStateVia == OperationFinalStateVia.OriginalUri))
+ {
+ return _originalUri.AbsoluteUri;
+ }
+
+ if (_originalHasLocation && _finalStateVia == OperationFinalStateVia.Location)
+ {
+ return _lastKnownLocation;
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
similarity index 99%
rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/PhArmOperation.cs
rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
index 9f293c1d5364..33318392c2fe 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/PhArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
@@ -33,7 +33,6 @@ protected PhArmOperation()
/// The results to wrap.
/// The function used to convert from existing type to new type.
public PhArmOperation(Operation wrapped, Func converter)
- : base(null)
{
_wrapped = wrapped;
_converter = converter;
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
new file mode 100644
index 000000000000..0bc1cac82911
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Core;
+
+namespace Azure.ResourceManager.Core
+{
+ internal class ValueArmOperation : ArmOperation
+ {
+ public override string Id => throw new NotImplementedException();
+
+ public override TOperations Value => throw new NotImplementedException();
+
+ public override bool HasCompleted => throw new NotImplementedException();
+
+ public override bool HasValue => throw new NotImplementedException();
+
+ public override Response GetRawResponse()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Response UpdateStatus(CancellationToken cancellationToken = default)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmVoidOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs
similarity index 85%
rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmVoidOperation.cs
rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs
index f0d24e3e714e..2a29a5f17b15 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmVoidOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs
@@ -10,32 +10,31 @@ namespace Azure.ResourceManager.Core
///
/// Generic ARM long running operation class for operations with no returned value
///
- public sealed class ArmVoidOperation : ArmOperation
+ internal sealed class VoidArmOperation : ArmOperation
{
- private readonly Operation _wrapped;
-
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The operation that has a response which has no body.
- public ArmVoidOperation(Operation other)
- : base(null)
+ public VoidArmOperation(Operation other)
{
if (other is null)
throw new ArgumentNullException(nameof(other));
_wrapped = other;
+ IsLongRunningOperation = true;
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The response which has no body.
- public ArmVoidOperation(Response other)
- : base(other)
+ public VoidArmOperation(Response other)
{
if (other is null)
throw new ArgumentNullException(nameof(other));
+
+ SyncValue = other;
}
///
@@ -45,10 +44,10 @@ public ArmVoidOperation(Response other)
public override Response Value => SyncValue;
///
- public override bool HasCompleted => CompletedSynchronously || _wrapped.HasCompleted;
+ public override bool HasCompleted => !IsLongRunningOperation || _wrapped.HasCompleted;
///
- public override bool HasValue => CompletedSynchronously || _wrapped.HasValue;
+ public override bool HasValue => !IsLongRunningOperation || _wrapped.HasValue;
///
public override Response GetRawResponse()
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs
index d5057ad8fa90..c3c1a1627b53 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs
@@ -70,15 +70,15 @@ protected ResourceGroupOperations(ResourceOperationsBase options, ResourceIdenti
/// When you delete a resource group, all of its resources are also deleted. Deleting a resource group deletes all of its template deployments and currently stored operations.
///
/// A token to allow the caller to cancel the call to the service. The default value is .
- /// A response with the operation for this resource.
- public virtual ArmResponse Delete(CancellationToken cancellationToken = default)
+ /// A response with the operation for this resource.
+ public virtual ArmResponse Delete(CancellationToken cancellationToken = default)
{
using var scope = Diagnostics.CreateScope("ResourceGroupOperations.Delete");
scope.Start();
try
{
- return new ArmResponse(Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletion(cancellationToken));
+ return ArmResponse.FromResponse(Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletion(cancellationToken));
}
catch (Exception e)
{
@@ -91,15 +91,15 @@ public virtual ArmResponse Delete(CancellationToken cancellationToken
/// When you delete a resource group, all of its resources are also deleted. Deleting a resource group deletes all of its template deployments and currently stored operations.
///
/// A token to allow the caller to cancel the call to the service. The default value is .
- /// A that on completion returns a response with the operation for this resource.
- public virtual async Task> DeleteAsync(CancellationToken cancellationToken = default)
+ /// A that on completion returns a response with the operation for this resource.
+ public virtual async Task DeleteAsync(CancellationToken cancellationToken = default)
{
using var scope = Diagnostics.CreateScope("ResourceGroupOperations.Delete");
scope.Start();
try
{
- return new ArmResponse(await Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false));
+ return ArmResponse.FromResponse(await Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false));
}
catch (Exception e)
{
@@ -123,7 +123,7 @@ public virtual ArmOperation StartDelete(CancellationToken cancellation
try
{
- return new ArmVoidOperation(Operations.StartDelete(Id.Name, cancellationToken));
+ return new VoidArmOperation(Operations.StartDelete(Id.Name, cancellationToken));
}
catch (Exception e)
{
@@ -147,7 +147,7 @@ public virtual async Task> StartDeleteAsync(CancellationT
try
{
- return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false));
+ return new VoidArmOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false));
}
catch (Exception e)
{
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs
new file mode 100644
index 000000000000..ebcfabfee872
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+
+namespace Azure.ResourceManager.Core
+{
+ ///
+ /// A class representing a response object from azure resource manager service.
+ ///
+ public abstract class ArmResponse : Response
+ {
+ ///
+ /// Creates a new instance of with the provided value and HTTP response.
+ ///
+ /// The type of the value.
+ /// The value.
+ /// The HTTP response.
+ /// A new instance of with the provided value and HTTP response.
+ /// Throws if response or value are null.
+ public static ArmResponse FromValue(TOperations value, ArmResponse response)
+ {
+ if (value is null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (response is null)
+ throw new ArgumentNullException(nameof(response));
+
+ return new ValueArmResponse(response, value);
+ }
+
+ ///
+ /// Creates a new instance of with the provided value and HTTP response.
+ ///
+ /// The HTTP response.
+ /// A new instance of with the provided value and HTTP response.
+ /// Throws if response is null.
+ public static ArmResponse FromResponse(Response response)
+ {
+ if (response is null)
+ throw new ArgumentNullException(nameof(response));
+
+ return new VoidArmResponse(response);
+ }
+ }
+
+ ///
+ /// A class representing a response object from azure resource manager service.
+ ///
+ /// The operations object return by the api call.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Allowed when we have a generic version of the same type")]
+ public abstract class ArmResponse : Response
+ {
+ ///
+ /// Returns the value of this object.
+ ///
+ /// The instance.
+ public static implicit operator TOperations(ArmResponse response) => response.Value;
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Adapters/PhArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/PhArmResponse.cs
similarity index 100%
rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/Adapters/PhArmResponse.cs
rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/PhArmResponse.cs
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs
new file mode 100644
index 000000000000..ab8ff5d5b71e
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Azure.ResourceManager.Core
+{
+ internal class ValueArmResponse : ArmResponse
+ {
+ private readonly ArmResponse _response;
+
+ public ValueArmResponse(ArmResponse response, TOperations value)
+ {
+ _response = response;
+ Value = value;
+ }
+
+ public override TOperations Value { get; }
+
+ public override Response GetRawResponse() => _response;
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs
new file mode 100644
index 000000000000..2132289a559a
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.IO;
+using Azure.Core;
+
+namespace Azure.ResourceManager.Core
+{
+ internal class VoidArmResponse : ArmResponse
+ {
+ private readonly Response _response;
+
+ public VoidArmResponse(Response response)
+ {
+ _response = response;
+ }
+
+ ///
+ public override int Status => _response.Status;
+
+ ///
+ public override string ReasonPhrase => _response.ReasonPhrase;
+
+ ///
+ public override Stream ContentStream
+ {
+ get => _response.ContentStream;
+ set => _response.ContentStream = value;
+ }
+
+ ///
+ public override string ClientRequestId
+ {
+ get => _response.ClientRequestId;
+ set => _response.ClientRequestId = value;
+ }
+
+ ///
+ public override void Dispose() => _response.Dispose();
+
+ ///
+ protected override bool ContainsHeader(string name) => _response.Headers.Contains(name);
+
+ ///
+ protected override IEnumerable EnumerateHeaders() => _response.Headers;
+
+ ///
+ protected override bool TryGetHeader(string name, out string value) => _response.Headers.TryGetValue(name, out value);
+
+ ///
+ protected override bool TryGetHeaderValues(string name, out IEnumerable values) => _response.Headers.TryGetValues(name, out values);
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
new file mode 100644
index 000000000000..b522100cb0e5
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Core;
+using Azure.Core.Pipeline;
+
+namespace Azure.ResourceManager.Core
+{
+ internal class UpdateResourceGroupOperation : ValueArmOperation, IOperationSource
+ {
+ public UpdateResourceGroupOperation()
+ {
+ }
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs
index 06e502e0ed5f..868671e7a9c3 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs
@@ -12,8 +12,7 @@ public class ArmResponseTests
[TestCase]
public void TestArmResponseParamCheck()
{
- Assert.Throws(() => { new ArmResponse(null); });
-
+ Assert.Throws(() => { ArmResponse.FromResponse(null); });
}
}
}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs
index 208c970bf67b..a042dd2bc58b 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs
@@ -13,8 +13,8 @@ public class ResourceTypeFilterTests
[TestCase]
public void TestResourceTypeFilterParamCheck()
{
- Assert.Throws(() => { new ArmVoidOperation((Operation)null); });
- Assert.Throws(() => { new ArmVoidOperation((Response)null); });
+ Assert.Throws(() => { new VoidArmOperation((Operation)null); });
+ Assert.Throws(() => { new VoidArmOperation((Response)null); });
}
}
}
From 0f52a38b28a28b150d2379add7062ade03b0d8c1 Mon Sep 17 00:00:00 2001
From: m-nash <64171366+m-nash@users.noreply.github.com>
Date: Wed, 24 Mar 2021 15:32:01 -0700
Subject: [PATCH 02/15] wip
---
.../src/Operation/ArmOperation.cs | 62 ++++++++--
.../src/Operation/PhArmOperation.cs | 16 ++-
.../src/Operation/ValueArmOperation.cs | 15 +--
.../src/Placeholder/ResourceGroupData.cs | 2 +-
.../ResourceGroupData.Serialization.cs | 111 ++++++++++++++++++
.../src/UpdateResourceGroupOperation.cs | 15 +++
6 files changed, 191 insertions(+), 30 deletions(-)
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
index 35d166888f62..062c123c82a4 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
@@ -5,13 +5,14 @@
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
+using Azure.Core.Pipeline;
namespace Azure.ResourceManager.Core
{
///
/// Abstract class for long-running or synchronous applications.
///
- public abstract class ArmOperation : ArmOperation, IOperationSource
+ public abstract class ArmOperation : ArmOperation
{
}
@@ -20,9 +21,12 @@ public abstract class ArmOperation : ArmOperation, IOperationSource
/// The to return representing the result of the ArmOperation.
#pragma warning disable SA1402 // File may only contain a single type
- public abstract class ArmOperation : Operation, IOperationSource
+ public abstract class ArmOperation : Operation
+ where TOperations : notnull, IUtf8JsonSerializable
#pragma warning restore SA1402 // File may only contain a single type
{
+ private readonly ArmOperationHelpers _operation;
+
///
/// Initializes a new instance of the class for mocking.
///
@@ -31,27 +35,63 @@ protected ArmOperation()
}
///
- /// Gets or sets the SyncValue
+ ///
///
- protected TOperations SyncValue { get; set; }
+ ///
+ protected ArmOperation(Operation operation)
+ {
+ WrappedOperation = operation;
+ }
///
- /// Gets or sets whether or not this is an LRO
+ ///
///
- protected bool IsLongRunningOperation { get; set; }
+ ///
+ protected ArmOperation(Response response)
+ {
+ WrappedResponse = response;
+ }
- ///
- public TOperations CreateResult(Response response, CancellationToken cancellationToken)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response)
{
- throw new NotImplementedException();
+ _operation = new ArmOperationHelpers(this, )
}
+ ///
+ ///
+ ///
+ protected Response WrappedResponse { get; private set; }
+
+ ///
+ ///
+ ///
+ protected Operation WrappedOperation { get; private set; }
+
///
- public ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken)
+ public override TOperations Value => WrappedOperation is null ? WrappedResponse.Value : WrappedOperation.Value;
+
+ ///
+ public override bool HasCompleted => WrappedResponse is null ? WrappedOperation.HasCompleted : true;
+
+ ///
+ public override bool HasValue => WrappedResponse is null ? WrappedOperation.HasValue : true;
+
+ ///
+ public override Response GetRawResponse()
{
- throw new NotImplementedException();
+ return WrappedResponse is null ? WrappedOperation.GetRawResponse() : WrappedResponse.GetRawResponse();
}
+ ///
+ public override string Id => WrappedOperation?.Id;
+
///
/// Waits for the completion of the long running operations.
///
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
index 33318392c2fe..f57461e7dd77 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
@@ -17,8 +17,7 @@ public class PhArmOperation : ArmOperation
where TModel : class
{
private readonly Func _converter;
- private readonly Response _syncWrapped;
- private readonly Operation _wrapped;
+ private readonly ArmOperation _wrapped;
///
/// Initializes a new instance of the class for mocking.
@@ -34,7 +33,7 @@ protected PhArmOperation()
/// The function used to convert from existing type to new type.
public PhArmOperation(Operation wrapped, Func converter)
{
- _wrapped = wrapped;
+ _wrapped = new ValueArmOperation(wrapped);
_converter = converter;
}
@@ -44,23 +43,22 @@ public PhArmOperation(Operation wrapped, Func conve
/// The results to wrap.
/// The function used to convert from existing type to new type.
public PhArmOperation(Response wrapped, Func converter)
- : base(converter(wrapped.Value))
{
+ _wrapped = new ValueArmOperation(wrapped);
_converter = converter;
- _syncWrapped = wrapped;
}
///
- public override string Id => _wrapped?.Id;
+ public override string Id => _wrapped.Id;
///
- public override TOperations Value => CompletedSynchronously ? SyncValue : _converter(_wrapped.Value);
+ public override TOperations Value => _converter(_wrapped.Value);
///
- public override bool HasCompleted => CompletedSynchronously || _wrapped.HasCompleted;
+ public override bool HasCompleted => _wrapped.HasCompleted;
///
- public override bool HasValue => CompletedSynchronously || _wrapped.HasValue;
+ public override bool HasValue => _wrapped.HasValue;
///
public override Response GetRawResponse()
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
index 0bc1cac82911..f418faad7a1d 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
@@ -12,17 +12,14 @@ namespace Azure.ResourceManager.Core
{
internal class ValueArmOperation : ArmOperation
{
- public override string Id => throw new NotImplementedException();
-
- public override TOperations Value => throw new NotImplementedException();
-
- public override bool HasCompleted => throw new NotImplementedException();
-
- public override bool HasValue => throw new NotImplementedException();
+ internal ValueArmOperation(Operation operation)
+ :base(operation)
+ {
+ }
- public override Response GetRawResponse()
+ internal ValueArmOperation(Response operation)
+ : base(operation)
{
- throw new NotImplementedException();
}
public override Response UpdateStatus(CancellationToken cancellationToken = default)
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs
index 175310efcb45..39615f9d399a 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs
@@ -10,7 +10,7 @@ namespace Azure.ResourceManager.Core
///
/// A class representing the ResourceGroup data model.
///
- public class ResourceGroupData : TrackedResource
+ public partial class ResourceGroupData : TrackedResource
{
///
/// Initializes a new instance of the class.
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs
new file mode 100644
index 000000000000..d430f210e2c1
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs
@@ -0,0 +1,111 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+//
+
+#nullable disable
+
+using System.Collections.Generic;
+using System.Text.Json;
+using Azure.Core;
+using Azure.ResourceManager.Resources.Models;
+
+namespace Azure.ResourceManager.Core
+{
+ public partial class ResourceGroupData : TrackedResource, IUtf8JsonSerializable
+ {
+ void IUtf8JsonSerializable.Write(Utf8JsonWriter writer)
+ {
+ writer.WriteStartObject();
+ if (Optional.IsDefined(Properties))
+ {
+ writer.WritePropertyName("properties");
+ writer.WriteObjectValue(Properties);
+ }
+ writer.WritePropertyName("location");
+ writer.WriteStringValue(Location);
+ if (Optional.IsDefined(ManagedBy))
+ {
+ writer.WritePropertyName("managedBy");
+ writer.WriteStringValue(ManagedBy);
+ }
+ if (Optional.IsCollectionDefined(Tags))
+ {
+ writer.WritePropertyName("tags");
+ writer.WriteStartObject();
+ foreach (var item in Tags)
+ {
+ writer.WritePropertyName(item.Key);
+ writer.WriteStringValue(item.Value);
+ }
+ writer.WriteEndObject();
+ }
+ writer.WriteEndObject();
+ }
+
+ internal static ResourceGroup DeserializeResourceGroup(JsonElement element)
+ {
+ Optional id = default;
+ Optional name = default;
+ Optional type = default;
+ Optional properties = default;
+ string location = default;
+ Optional managedBy = default;
+ Optional> tags = default;
+ foreach (var property in element.EnumerateObject())
+ {
+ if (property.NameEquals("id"))
+ {
+ id = property.Value.GetString();
+ continue;
+ }
+ if (property.NameEquals("name"))
+ {
+ name = property.Value.GetString();
+ continue;
+ }
+ if (property.NameEquals("type"))
+ {
+ type = property.Value.GetString();
+ continue;
+ }
+ if (property.NameEquals("properties"))
+ {
+ if (property.Value.ValueKind == JsonValueKind.Null)
+ {
+ property.ThrowNonNullablePropertyIsNull();
+ continue;
+ }
+ properties = ResourceGroupProperties.DeserializeResourceGroupProperties(property.Value);
+ continue;
+ }
+ if (property.NameEquals("location"))
+ {
+ location = property.Value.GetString();
+ continue;
+ }
+ if (property.NameEquals("managedBy"))
+ {
+ managedBy = property.Value.GetString();
+ continue;
+ }
+ if (property.NameEquals("tags"))
+ {
+ if (property.Value.ValueKind == JsonValueKind.Null)
+ {
+ property.ThrowNonNullablePropertyIsNull();
+ continue;
+ }
+ Dictionary dictionary = new Dictionary();
+ foreach (var property0 in property.Value.EnumerateObject())
+ {
+ dictionary.Add(property0.Name, property0.Value.GetString());
+ }
+ tags = dictionary;
+ continue;
+ }
+ }
+ return new ResourceGroupData(new Azure.ResourceManager.Resources.Models.ResourceGroup(id.Value, name.Value, type.Value, properties.Value, location, managedBy.Value, Optional.ToDictionary(tags)));
+ }
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
index b522100cb0e5..be85a7c39829 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
@@ -13,8 +14,22 @@ namespace Azure.ResourceManager.Core
{
internal class UpdateResourceGroupOperation : ValueArmOperation, IOperationSource
{
+ private readonly ArmOperationHelpers _operation;
+
public UpdateResourceGroupOperation()
{
}
+
+ ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken)
+ {
+ using var document = JsonDocument.Parse(response.ContentStream);
+ return ResourceGroup.DeserializeGalleryImage(document.RootElement);
+ }
+
+ async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken)
+ {
+ using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false);
+ return ResourceGroup.DeserializeGalleryImage(document.RootElement);
+ }
}
}
From 10f6ad0c6416ee7b84427b30a3068fec2005e6aa Mon Sep 17 00:00:00 2001
From: YalinLi0312
Date: Wed, 24 Mar 2021 16:18:02 -0700
Subject: [PATCH 03/15] Change the accessbility to virtual for Resource.Id
---
.../Azure.ResourceManager.Core/src/Resources/Resource.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs
index 86a35ac05cf7..a8638d1c689b 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs
@@ -14,7 +14,7 @@ public abstract class Resource : IEquatable, IEquatable, IComp
///
/// Gets or sets the resource identifier.
///
- public abstract ResourceIdentifier Id { get; protected set; }
+ public virtual ResourceIdentifier Id { get; protected set; }
///
/// Gets the name.
From c192698cae8165780a38f5aa7852164de3dd341e Mon Sep 17 00:00:00 2001
From: m-nash
Date: Wed, 31 Mar 2021 20:55:31 -0700
Subject: [PATCH 04/15] update strawman for operation changes
---
.../src/GenericResourceOperations.cs | 10 +-
.../src/IDeletableResource.cs | 4 +-
.../UpdateResourceGroupOperation.cs | 51 +++
.../src/Operation/ArmOperation.cs | 212 ++++++++--
.../src/Operation/ArmOperationHelpers.cs | 369 ------------------
.../src/Operation/PhArmOperation.cs | 73 ++--
.../src/Operation/PhVoidArmOperation.cs | 113 ++++++
.../src/Operation/ValueArmOperation.cs | 32 --
.../src/Operation/VoidArmOperation.cs | 101 +----
.../src/ResourceGroupContainer.cs | 4 +-
.../src/ResourceGroupOperations.cs | 8 +-
.../ResourceGroupData.Serialization.cs | 111 ------
.../src/UpdateResourceGroupOperation.cs | 35 --
.../tests/Unit/ResourceTypeFilterTests.cs | 1 -
14 files changed, 402 insertions(+), 722 deletions(-)
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs
delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs
delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs
delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs
index e53570b8f9ae..b01c039d80cf 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs
@@ -77,9 +77,9 @@ public async Task DeleteAsync(CancellationToken cancellationToken =
///
/// Details on long running operation object.
///
- public ArmOperation StartDelete(CancellationToken cancellationToken = default)
+ public ArmOperation StartDelete(CancellationToken cancellationToken = default)
{
- return new VoidArmOperation(Operations.StartDeleteById(Id, GetApiVersion(cancellationToken), cancellationToken));
+ return new PhVoidArmOperation(Operations.StartDeleteById(Id, GetApiVersion(cancellationToken), cancellationToken));
}
///
@@ -93,10 +93,10 @@ public ArmOperation StartDelete(CancellationToken cancellationToken =
///
/// Details on long running operation object.
///
- public async Task> StartDeleteAsync(CancellationToken cancellationToken = default)
+ public async Task StartDeleteAsync(CancellationToken cancellationToken = default)
{
var operation = await Operations.StartDeleteByIdAsync(Id, await GetApiVersionAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
- return new VoidArmOperation(operation);
+ return new PhVoidArmOperation(operation);
}
///
@@ -126,7 +126,7 @@ public ArmOperation StartAddTag(string key, string value, Cance
GenericResource resource = GetResource();
resource.Data.Tags[key] = value;
return new PhArmOperation(
- Operations.StartUpdateById(Id, GetApiVersion(cancellationToken), resource.Data, cancellationToken).WaitForCompletionAsync(cancellationToken).EnsureCompleted(),
+ Operations.StartUpdateById(Id, GetApiVersion(cancellationToken), resource.Data, cancellationToken),
v => new GenericResource(this, new GenericResourceData(v)));
}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs
index fd799644ae3f..f77a93d5dedf 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs
@@ -34,7 +34,7 @@ public interface IDeletableResource
///
/// Details on long running operation object.
///
- ArmOperation StartDelete(CancellationToken cancellationToken = default);
+ ArmOperation StartDelete(CancellationToken cancellationToken = default);
///
/// Delete the resource. This call returns a Task that blocks until the delete operation is accepted on the service.
@@ -47,6 +47,6 @@ public interface IDeletableResource
///
/// Details on long running operation object.
///
- Task> StartDeleteAsync(CancellationToken cancellationToken = default);
+ Task StartDeleteAsync(CancellationToken cancellationToken = default);
}
}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs
new file mode 100644
index 000000000000..12b58c4a8966
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Core;
+
+namespace Azure.ResourceManager.Core
+{
+ internal class UpdateResourceGroupOperation : ArmOperation, IOperationSource
+ {
+ private readonly ResourceOperationsBase _operations;
+
+ protected UpdateResourceGroupOperation()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The operation source to use.
+ /// The arm operations object to copy from.
+ /// The original request.
+ /// The original response.
+ internal UpdateResourceGroupOperation(IOperationSource source, ResourceOperationsBase operations, Request request, Response response)
+ : base(source, operations.Diagnostics, ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), request, response, "UpdateResourceGroupOperation")
+ {
+ _operations = operations;
+ }
+
+ ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken)
+ {
+ using var document = JsonDocument.Parse(response.ContentStream);
+ return GetResourceGrouop(document);
+ }
+
+ private ResourceGroup GetResourceGrouop(JsonDocument document)
+ {
+ var method = typeof(ResourceManager.Resources.Models.ResourceGroup).GetMethod("DeserializeResourceGroup", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+ var obj = method.Invoke(null, new object[] { document.RootElement });
+ return new ResourceGroup(_operations, new ResourceGroupData(obj as ResourceManager.Resources.Models.ResourceGroup));
+ }
+
+ async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken)
+ {
+ using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false);
+ return GetResourceGrouop(document);
+ }
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
index 062c123c82a4..91029ec2b479 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
@@ -12,8 +12,128 @@ namespace Azure.ResourceManager.Core
///
/// Abstract class for long-running or synchronous applications.
///
- public abstract class ArmOperation : ArmOperation
+ public abstract class ArmOperation : Operation
{
+ private readonly ArmOperationHelpers _operation;
+ private readonly Response _voidResponse;
+
+ ///
+ /// Initializes a new instance of the class for mocking.
+ ///
+ protected ArmOperation()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The operation source to use.
+ /// The client diagnostics to use.
+ /// The HttpPipeline to use.
+ /// The original request.
+ /// The original response.
+ /// The scope name to use.
+ internal ArmOperation(IOperationSource source, ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, string scopeName)
+ {
+ _operation = new ArmOperationHelpers(source, clientDiagnostics, pipeline, request, response, OperationFinalStateVia.Location, scopeName);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ protected ArmOperation(Response response)
+ {
+ if (response is null)
+ throw new ArgumentNullException(nameof(response));
+
+ _voidResponse = response;
+ }
+
+ ///
+ private bool _doesWrapOperation => _voidResponse is null;
+
+ ///
+ public override string Id => _operation?.Id;
+
+ ///
+ public override Response Value => throw new InvalidOperationException();
+
+ ///
+ public override bool HasCompleted => _doesWrapOperation ? _operation.HasCompleted : true;
+
+ ///
+ public override bool HasValue => false;
+
+ ///
+ public override Response GetRawResponse()
+ {
+ return _doesWrapOperation ? _operation.GetRawResponse() : _voidResponse;
+ }
+
+ ///
+ public override Response UpdateStatus(CancellationToken cancellationToken = default)
+ {
+ return _doesWrapOperation ? _operation.UpdateStatus(cancellationToken) : _voidResponse;
+ }
+
+ ///
+ public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default)
+ {
+ return _doesWrapOperation
+ ? _operation.UpdateStatusAsync(cancellationToken)
+ : new ValueTask(_voidResponse);
+ }
+
+ ///
+ public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default)
+ {
+ return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken)
+ {
+ return _doesWrapOperation
+ ? await _operation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false)
+ : Response.FromValue(_voidResponse, _voidResponse);
+ }
+
+ ///
+ /// Waits for the completion of the long running operations.
+ ///
+ /// A token to allow the caller to cancel the call to the service. The default value is .
+ /// A response with the operation for this resource.
+ ///
+ /// Details on long running operation object.
+ ///
+ public virtual Response WaitForCompletion(CancellationToken cancellationToken = default)
+ {
+ return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken);
+ }
+
+ ///
+ /// Waits for the completion of the long running operations.
+ ///
+ /// The polling interval in seconds to check for status.
+ /// A token to allow the caller to cancel the call to the service. The default value is .
+ /// A response with the operation for this resource.
+ ///
+ /// Details on long running operation object.
+ ///
+ public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default)
+ {
+ while (true)
+ {
+ UpdateStatus(cancellationToken);
+ if (HasCompleted)
+ {
+ return new VoidArmResponse(GetRawResponse());
+ }
+
+ Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken);
+ }
+ }
}
///
@@ -22,10 +142,11 @@ public abstract class ArmOperation : ArmOperation
/// The to return representing the result of the ArmOperation.
#pragma warning disable SA1402 // File may only contain a single type
public abstract class ArmOperation : Operation
- where TOperations : notnull, IUtf8JsonSerializable
+ where TOperations : notnull
#pragma warning restore SA1402 // File may only contain a single type
{
private readonly ArmOperationHelpers _operation;
+ private readonly Response _valueResponse;
///
/// Initializes a new instance of the class for mocking.
@@ -35,62 +156,81 @@ protected ArmOperation()
}
///
- ///
+ /// Initializes a new instance of the class.
///
- ///
- protected ArmOperation(Operation operation)
- {
- WrappedOperation = operation;
- }
-
- ///
- ///
- ///
- ///
+ /// The non lro response to wrap.
protected ArmOperation(Response response)
{
- WrappedResponse = response;
+ if (response is null)
+ throw new ArgumentNullException(nameof(response));
+
+ _valueResponse = response;
}
///
- ///
+ /// Initializes a new instance of the class.
///
- ///
- ///
- ///
- ///
- protected ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response)
+ /// The operation source to use.
+ /// The client diagnostics to use.
+ /// The HttpPipeline to use.
+ /// The original request.
+ /// The original response.
+ /// The scope name to use.
+ internal ArmOperation(IOperationSource source, ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, string scopeName)
{
- _operation = new ArmOperationHelpers(this, )
+ _operation = new ArmOperationHelpers(source, clientDiagnostics, pipeline, request, response, OperationFinalStateVia.Location, scopeName);
}
- ///
- ///
- ///
- protected Response WrappedResponse { get; private set; }
+ private bool _doesWrapOperation => _valueResponse is null;
- ///
- ///
- ///
- protected Operation WrappedOperation { get; private set; }
+ ///
+ public override string Id => _operation?.Id;
///
- public override TOperations Value => WrappedOperation is null ? WrappedResponse.Value : WrappedOperation.Value;
+ public override TOperations Value => _doesWrapOperation ? _operation.Value : _valueResponse.Value;
///
- public override bool HasCompleted => WrappedResponse is null ? WrappedOperation.HasCompleted : true;
+ public override bool HasCompleted => _doesWrapOperation ? _operation.HasCompleted : true;
///
- public override bool HasValue => WrappedResponse is null ? WrappedOperation.HasValue : true;
+ public override bool HasValue => _doesWrapOperation ? _operation.HasValue : true;
///
public override Response GetRawResponse()
{
- return WrappedResponse is null ? WrappedOperation.GetRawResponse() : WrappedResponse.GetRawResponse();
+ return _doesWrapOperation ? _operation.GetRawResponse() : _valueResponse.GetRawResponse();
}
///
- public override string Id => WrappedOperation?.Id;
+ public override Response UpdateStatus(CancellationToken cancellationToken = default)
+ {
+ return _doesWrapOperation ? _operation.UpdateStatus(cancellationToken) : _valueResponse.GetRawResponse();
+ }
+
+ ///
+ public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default)
+ {
+ return _doesWrapOperation
+ ? _operation.UpdateStatusAsync(cancellationToken)
+ : new ValueTask(_valueResponse.GetRawResponse());
+ }
+
+ ///
+ public override async ValueTask> WaitForCompletionAsync(
+ CancellationToken cancellationToken = default)
+ {
+ return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ public override async ValueTask> WaitForCompletionAsync(
+ TimeSpan pollingInterval,
+ CancellationToken cancellationToken)
+ {
+ return _doesWrapOperation
+ ? await _operation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false)
+ : _valueResponse;
+ }
///
/// Waits for the completion of the long running operations.
@@ -100,7 +240,7 @@ public override Response GetRawResponse()
///
/// Details on long running operation object.
///
- public ArmResponse WaitForCompletion(CancellationToken cancellationToken = default)
+ public virtual Response WaitForCompletion(CancellationToken cancellationToken = default)
{
return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken);
}
@@ -114,7 +254,7 @@ public ArmResponse WaitForCompletion(CancellationToken cancellation
///
/// Details on long running operation object.
///
- public ArmResponse WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default)
+ public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default)
{
while (true)
{
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs
deleted file mode 100644
index 96ffbdbb9d99..000000000000
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs
+++ /dev/null
@@ -1,369 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-#nullable enable
-
-using System;
-using System.Linq;
-using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.Core;
-using Azure.Core.Pipeline;
-
-namespace Azure.ResourceManager.Core
-{
- ///
- /// This implements the ARM scenarios for LROs. It is highly recommended to read the ARM spec prior to modifying this code:
- /// https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/Addendum.md#asynchronous-operations
- /// Other reference documents include:
- /// https://github.com/Azure/autorest/blob/master/docs/extensions/readme.md#x-ms-long-running-operation
- /// https://github.com/Azure/adx-documentation-pr/blob/master/sdks/LRO/LRO_AzureSDK.md
- ///
- /// The final result of the LRO.
- internal class ArmOperationHelpers
- {
- public static TimeSpan DefaultPollingInterval { get; } = TimeSpan.FromSeconds(1);
-
- private static readonly string[] s_failureStates = { "failed", "canceled" };
- private static readonly string[] s_terminalStates = { "succeeded", "failed", "canceled" };
-
- private readonly HttpPipeline _pipeline;
- private readonly ClientDiagnostics _clientDiagnostics;
- private readonly string _scopeName;
- private readonly RequestMethod _requestMethod;
- private readonly Uri _originalUri;
- private readonly OperationFinalStateVia _finalStateVia;
- private HeaderFrom _headerFrom;
- private string _pollUri = default!;
- private bool _originalHasLocation;
- private string? _lastKnownLocation;
-
- private readonly IOperationSource _source;
- private Response _rawResponse;
- private T _value = default!;
- private bool _hasValue;
- private bool _hasCompleted;
- private bool _shouldPoll;
-
- public ArmOperationHelpers(
- IOperationSource source,
- ClientDiagnostics clientDiagnostics,
- HttpPipeline pipeline,
- Request originalRequest,
- Response originalResponse,
- OperationFinalStateVia finalStateVia,
- string scopeName)
- {
- _source = source;
- _rawResponse = originalResponse;
- _requestMethod = originalRequest.Method;
- _originalUri = originalRequest.Uri.ToUri();
- _finalStateVia = finalStateVia;
- InitializeScenarioInfo();
-
- _pipeline = pipeline;
- _clientDiagnostics = clientDiagnostics;
- _scopeName = scopeName;
- // When the original response has no headers, we do not start polling immediately.
- _shouldPoll = _headerFrom != HeaderFrom.None;
- }
-
- public Response GetRawResponse() => _rawResponse;
-
- public ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default)
- {
- return WaitForCompletionAsync(DefaultPollingInterval, cancellationToken);
- }
-
- public async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken)
- {
- while (true)
- {
- await UpdateStatusAsync(cancellationToken).ConfigureAwait(false);
- if (HasCompleted)
- {
- return Response.FromValue(Value, GetRawResponse());
- }
-
- await Task.Delay(pollingInterval, cancellationToken).ConfigureAwait(false);
- }
- }
-
- private async ValueTask UpdateStatusAsync(bool async, CancellationToken cancellationToken)
- {
- if (_hasCompleted)
- {
- return GetRawResponse();
- }
-
- if (_shouldPoll)
- {
- UpdatePollUri();
- _rawResponse = async
- ? await GetResponseAsync(_pollUri, cancellationToken).ConfigureAwait(false)
- : GetResponse(_pollUri, cancellationToken);
- }
-
- _shouldPoll = true;
- _hasCompleted = IsTerminalState(out string state);
- if (_hasCompleted)
- {
- Response finalResponse = GetRawResponse();
- if (s_failureStates.Contains(state))
- {
- throw _clientDiagnostics.CreateRequestFailedException(finalResponse);
- }
-
- string? finalUri = GetFinalUri();
- if (finalUri != null)
- {
- finalResponse = async
- ? await GetResponseAsync(finalUri, cancellationToken).ConfigureAwait(false)
- : GetResponse(finalUri, cancellationToken);
- }
-
- switch (finalResponse.Status)
- {
- case 200:
- case 201 when _requestMethod == RequestMethod.Put:
- case 204 when !(_requestMethod == RequestMethod.Put || _requestMethod == RequestMethod.Patch):
- {
- _value = async
- ? await _source.CreateResultAsync(finalResponse, cancellationToken).ConfigureAwait(false)
- : _source.CreateResult(finalResponse, cancellationToken);
- _rawResponse = finalResponse;
- _hasValue = true;
- break;
- }
- default:
- throw _clientDiagnostics.CreateRequestFailedException(finalResponse);
- }
- }
-
- return GetRawResponse();
- }
-
- public async ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => await UpdateStatusAsync(async: true, cancellationToken).ConfigureAwait(false);
-
- public Response UpdateStatus(CancellationToken cancellationToken = default) => UpdateStatusAsync(async: false, cancellationToken).EnsureCompleted();
-
-#pragma warning disable CA1822
- //TODO: This is currently unused.
- public string Id => throw new NotImplementedException();
-#pragma warning restore CA1822
-
- public T Value
- {
- get
- {
- if (!HasValue)
- {
- throw new InvalidOperationException("The operation has not completed yet.");
- }
-
- return _value;
- }
- }
-
- public bool HasCompleted => _hasCompleted;
- public bool HasValue => _hasValue;
-
- private HttpMessage CreateRequest(string link)
- {
- HttpMessage message = _pipeline.CreateMessage();
- Request request = message.Request;
- request.Method = RequestMethod.Get;
-
- if (Uri.TryCreate(link, UriKind.Absolute, out var nextLink) && nextLink.Scheme != "file")
- {
- request.Uri.Reset(nextLink);
- }
- else
- {
- request.Uri.Reset(new Uri(_originalUri, link));
- }
-
- return message;
- }
-
- private async ValueTask GetResponseAsync(string link, CancellationToken cancellationToken = default)
- {
- if (link == null)
- {
- throw new ArgumentNullException(nameof(link));
- }
-
- using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName);
- scope.Start();
- try
- {
- using HttpMessage message = CreateRequest(link);
- await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);
- return message.Response;
- }
- catch (Exception e)
- {
- scope.Failed(e);
- throw;
- }
- }
-
- private Response GetResponse(string link, CancellationToken cancellationToken = default)
- {
- if (link == null)
- {
- throw new ArgumentNullException(nameof(link));
- }
-
- using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName);
- scope.Start();
- try
- {
- using HttpMessage message = CreateRequest(link);
- _pipeline.Send(message, cancellationToken);
- return message.Response;
- }
- catch (Exception e)
- {
- scope.Failed(e);
- throw;
- }
- }
-
- private bool IsTerminalState(out string state)
- {
- Response response = GetRawResponse();
- state = string.Empty;
- if (_headerFrom == HeaderFrom.Location)
- {
- return response.Status != 202;
- }
-
- if (response.Status >= 200 && response.Status <= 204)
- {
- if (response.ContentStream?.Length > 0)
- {
- try
- {
- using JsonDocument document = JsonDocument.Parse(response.ContentStream);
- foreach (JsonProperty property in document.RootElement.EnumerateObject())
- {
- if ((_headerFrom == HeaderFrom.OperationLocation ||
- _headerFrom == HeaderFrom.AzureAsyncOperation) &&
- property.NameEquals("status"))
- {
- state = property.Value.GetString().ToLowerInvariant();
- return s_terminalStates.Contains(state);
- }
-
- if (_headerFrom == HeaderFrom.None && property.NameEquals("properties"))
- {
- foreach (JsonProperty innerProperty in property.Value.EnumerateObject())
- {
- if (innerProperty.NameEquals("provisioningState"))
- {
- state = innerProperty.Value.GetString().ToLowerInvariant();
- return s_terminalStates.Contains(state);
- }
- }
- }
- }
- }
- finally
- {
- // It is required to reset the position of the content after reading as this response may be used for deserialization.
- response.ContentStream.Position = 0;
- }
- }
-
- // If provisioningState was not found, it defaults to Succeeded.
- if (_headerFrom == HeaderFrom.None)
- {
- return true;
- }
- }
-
- throw _clientDiagnostics.CreateRequestFailedException(response);
- }
-
- private enum HeaderFrom
- {
- None,
- OperationLocation,
- AzureAsyncOperation,
- Location
- }
-
- private void InitializeScenarioInfo()
- {
- _originalHasLocation = _rawResponse.Headers.Contains("Location");
-
- if (_rawResponse.Headers.Contains("Operation-Location"))
- {
- _headerFrom = HeaderFrom.OperationLocation;
- return;
- }
-
- if (_rawResponse.Headers.Contains("Azure-AsyncOperation"))
- {
- _headerFrom = HeaderFrom.AzureAsyncOperation;
- return;
- }
-
- if (_originalHasLocation)
- {
- _headerFrom = HeaderFrom.Location;
- return;
- }
-
- _pollUri = _originalUri.AbsoluteUri;
- _headerFrom = HeaderFrom.None;
- }
-
- private void UpdatePollUri()
- {
- var hasLocation = _rawResponse.Headers.TryGetValue("Location", out string? location);
- if (hasLocation)
- {
- _lastKnownLocation = location;
- }
-
- switch (_headerFrom)
- {
- case HeaderFrom.OperationLocation when _rawResponse.Headers.TryGetValue("Operation-Location", out string? operationLocation):
- _pollUri = operationLocation;
- return;
- case HeaderFrom.AzureAsyncOperation when _rawResponse.Headers.TryGetValue("Azure-AsyncOperation", out string? azureAsyncOperation):
- _pollUri = azureAsyncOperation;
- return;
- case HeaderFrom.Location when hasLocation:
- _pollUri = location!;
- return;
- }
- }
-
- private string? GetFinalUri()
- {
- if (_headerFrom == HeaderFrom.OperationLocation || _headerFrom == HeaderFrom.AzureAsyncOperation)
- {
- if (_requestMethod == RequestMethod.Delete)
- {
- return null;
- }
-
- if (_requestMethod == RequestMethod.Put || (_originalHasLocation && _finalStateVia == OperationFinalStateVia.OriginalUri))
- {
- return _originalUri.AbsoluteUri;
- }
-
- if (_originalHasLocation && _finalStateVia == OperationFinalStateVia.Location)
- {
- return _lastKnownLocation;
- }
- }
-
- return null;
- }
- }
-}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
index f57461e7dd77..df48e26e9ecd 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs
@@ -4,6 +4,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using Azure.Core;
namespace Azure.ResourceManager.Core
{
@@ -17,7 +18,8 @@ public class PhArmOperation : ArmOperation
where TModel : class
{
private readonly Func _converter;
- private readonly ArmOperation _wrapped;
+ private readonly Operation _wrappedOperation;
+ private readonly ArmOperation _wrappedResponseOperation;
///
/// Initializes a new instance of the class for mocking.
@@ -33,7 +35,7 @@ protected PhArmOperation()
/// The function used to convert from existing type to new type.
public PhArmOperation(Operation wrapped, Func converter)
{
- _wrapped = new ValueArmOperation(wrapped);
+ _wrappedOperation = wrapped;
_converter = converter;
}
@@ -44,63 +46,80 @@ public PhArmOperation(Operation wrapped, Func conve
/// The function used to convert from existing type to new type.
public PhArmOperation(Response wrapped, Func converter)
{
- _wrapped = new ValueArmOperation(wrapped);
+ _wrappedResponseOperation = new ValueArmOperation(wrapped);
_converter = converter;
}
+ private bool _doesWrapOperation => _wrappedResponseOperation is null;
+
///
- public override string Id => _wrapped.Id;
+ public override string Id => _wrappedOperation?.Id;
///
- public override TOperations Value => _converter(_wrapped.Value);
+ public override TOperations Value => _converter(_doesWrapOperation ? _wrappedOperation.Value : _wrappedResponseOperation.Value);
///
- public override bool HasCompleted => _wrapped.HasCompleted;
+ public override bool HasCompleted => _doesWrapOperation ? _wrappedOperation.HasCompleted : _wrappedResponseOperation.HasCompleted;
///
- public override bool HasValue => _wrapped.HasValue;
+ public override bool HasValue => _doesWrapOperation ? _wrappedOperation.HasValue : _wrappedResponseOperation.HasValue;
///
public override Response GetRawResponse()
{
- return CompletedSynchronously ? _syncWrapped.GetRawResponse() : _wrapped.GetRawResponse();
+ return _doesWrapOperation ? _wrappedOperation.GetRawResponse() : _wrappedResponseOperation.GetRawResponse();
}
///
public override Response UpdateStatus(CancellationToken cancellationToken = default)
{
- return CompletedSynchronously ? _syncWrapped.GetRawResponse() : _wrapped.UpdateStatus(cancellationToken);
+ return _doesWrapOperation ? _wrappedOperation.UpdateStatus(cancellationToken) : _wrappedResponseOperation.UpdateStatus(cancellationToken);
}
///
public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default)
{
- return CompletedSynchronously
- ? new ValueTask(_syncWrapped.GetRawResponse())
- : _wrapped.UpdateStatusAsync(cancellationToken);
+ return _doesWrapOperation
+ ? _wrappedOperation.UpdateStatusAsync(cancellationToken)
+ : _wrappedResponseOperation.UpdateStatusAsync(cancellationToken);
+ }
+
+ ///
+ public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default)
+ {
+ var task = WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken);
+ return await task.ConfigureAwait(false);
}
///
- public override async ValueTask> WaitForCompletionAsync(
- CancellationToken cancellationToken = default)
+ public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken)
{
- return CompletedSynchronously
- ? new PhArmResponse(_syncWrapped, _converter)
- : new PhArmResponse(
- await _wrapped.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false),
- _converter);
+ var task = _doesWrapOperation
+ ? _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken)
+ : _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken);
+ var value = await task.ConfigureAwait(false);
+ return Response.FromValue(_converter(value), GetRawResponse());
}
///
- public override async ValueTask> WaitForCompletionAsync(
- TimeSpan pollingInterval,
- CancellationToken cancellationToken)
+ public override Response WaitForCompletion(CancellationToken cancellationToken = default)
{
- return CompletedSynchronously
- ? new PhArmResponse(_syncWrapped, _converter)
- : new PhArmResponse(
- await _wrapped.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false),
- _converter);
+ return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken);
+ }
+
+ ///
+ public override Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default)
+ {
+ while (true)
+ {
+ UpdateStatus(cancellationToken);
+ if (HasCompleted)
+ {
+ return Response.FromValue(Value, GetRawResponse()) as ArmResponse;
+ }
+
+ Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken);
+ }
}
}
}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs
new file mode 100644
index 000000000000..2c94407f519b
--- /dev/null
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs
@@ -0,0 +1,113 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Core;
+
+namespace Azure.ResourceManager.Core
+{
+ ///
+ /// A calss representing an arm operation wrapper object.
+ ///
+ public class PhVoidArmOperation : ArmOperation
+ {
+ private readonly Operation _wrappedOperation;
+ private readonly ArmOperation _wrappedResponseOperation;
+
+ ///
+ /// Initializes a new instance of the class for mocking.
+ ///
+ protected PhVoidArmOperation()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The results to wrap.
+ public PhVoidArmOperation(Operation wrapped)
+ {
+ _wrappedOperation = wrapped;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The results to wrap.
+ public PhVoidArmOperation(Response wrapped)
+ {
+ _wrappedResponseOperation = new VoidArmOperation(wrapped);
+ }
+
+ private bool _doesWrapOperation => _wrappedResponseOperation is null;
+
+ ///
+ public override string Id => _wrappedOperation?.Id;
+
+ ///
+ public override Response Value => throw new InvalidOperationException();
+
+ ///
+ public override bool HasCompleted => _doesWrapOperation ? _wrappedOperation.HasCompleted : _wrappedResponseOperation.HasCompleted;
+
+ ///
+ public override bool HasValue => false;
+
+ ///
+ public override Response GetRawResponse()
+ {
+ return _doesWrapOperation ? _wrappedOperation.GetRawResponse() : _wrappedResponseOperation.GetRawResponse();
+ }
+
+ ///
+ public override Response UpdateStatus(CancellationToken cancellationToken = default)
+ {
+ return _doesWrapOperation ? _wrappedOperation.UpdateStatus(cancellationToken) : _wrappedResponseOperation.UpdateStatus(cancellationToken);
+ }
+
+ ///
+ public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default)
+ {
+ return _doesWrapOperation
+ ? _wrappedOperation.UpdateStatusAsync(cancellationToken)
+ : _wrappedResponseOperation.UpdateStatusAsync(cancellationToken);
+ }
+
+ ///
+ public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default)
+ {
+ return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken)
+ {
+ return _doesWrapOperation
+ ? Response.FromValue(await _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false), _wrappedOperation.GetRawResponse())
+ : Response.FromValue(await _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false), _wrappedOperation.GetRawResponse());
+ }
+
+ ///
+ public override Response WaitForCompletion(CancellationToken cancellationToken = default)
+ {
+ return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken);
+ }
+
+ ///
+ public override Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default)
+ {
+ while (true)
+ {
+ UpdateStatus(cancellationToken);
+ if (HasCompleted)
+ {
+ return Response.FromValue(Value, GetRawResponse());
+ }
+
+ Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken);
+ }
+ }
+ }
+}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
index f418faad7a1d..e546235de64d 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
@@ -1,45 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.Core;
-
namespace Azure.ResourceManager.Core
{
internal class ValueArmOperation : ArmOperation
{
- internal ValueArmOperation(Operation operation)
- :base(operation)
- {
- }
-
internal ValueArmOperation(Response operation)
: base(operation)
{
}
-
- public override Response UpdateStatus(CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
- public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
- public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
- public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
}
}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs
index 2a29a5f17b15..07f2d6679f3f 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs
@@ -1,10 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
namespace Azure.ResourceManager.Core
{
///
@@ -15,101 +11,10 @@ internal sealed class VoidArmOperation : ArmOperation
///
/// Initializes a new instance of the class.
///
- /// The operation that has a response which has no body.
- public VoidArmOperation(Operation other)
- {
- if (other is null)
- throw new ArgumentNullException(nameof(other));
-
- _wrapped = other;
- IsLongRunningOperation = true;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The response which has no body.
- public VoidArmOperation(Response other)
- {
- if (other is null)
- throw new ArgumentNullException(nameof(other));
-
- SyncValue = other;
- }
-
- ///
- public override string Id => _wrapped?.Id;
-
- ///
- public override Response Value => SyncValue;
-
- ///
- public override bool HasCompleted => !IsLongRunningOperation || _wrapped.HasCompleted;
-
- ///
- public override bool HasValue => !IsLongRunningOperation || _wrapped.HasValue;
-
- ///
- public override Response GetRawResponse()
- {
- return CompletedSynchronously ? SyncValue : _wrapped.GetRawResponse();
- }
-
- ///
- public override Response UpdateStatus(CancellationToken cancellationToken = default)
- {
- return CompletedSynchronously ? SyncValue : _wrapped.UpdateStatus(cancellationToken);
- }
-
- ///
- public override async ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default)
- {
- return CompletedSynchronously ? SyncValue : await _wrapped.UpdateStatusAsync(cancellationToken).ConfigureAwait(false);
- }
-
- ///
- public override async ValueTask> WaitForCompletionAsync(
- CancellationToken cancellationToken = default)
- {
- return CompletedSynchronously
- ? new WrappingResponse(SyncValue)
- : await _wrapped.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false);
- }
-
- ///
- public override async ValueTask> WaitForCompletionAsync(
- TimeSpan pollingInterval,
- CancellationToken cancellationToken)
- {
- return CompletedSynchronously
- ? new WrappingResponse(SyncValue)
- : await _wrapped.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false);
- }
-
- ///
- /// A class which wraps a response with no body.
- ///
- internal class WrappingResponse : ArmResponse
+ /// The response which has no body.
+ internal VoidArmOperation(Response response)
+ : base(response)
{
- private readonly Response _wrapped;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The response object to wrap.
- public WrappingResponse(Response wrapped)
- {
- _wrapped = wrapped;
- }
-
- ///
- public override Response Value => _wrapped;
-
- ///
- public override Response GetRawResponse()
- {
- return _wrapped;
- }
}
}
}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs
index 5a88837c374b..f516a406a80f 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs
@@ -133,8 +133,8 @@ public override ArmOperation StartCreateOrUpdate(string name, Res
try
{
return new PhArmOperation(
- Operations.CreateOrUpdate(name, resourceDetails, cancellationToken),
- g => new ResourceGroup(Parent, new ResourceGroupData(g)));
+ Operations.CreateOrUpdate(name, resourceDetails, cancellationToken),
+ g => new ResourceGroup(Parent, new ResourceGroupData(g)));
}
catch (Exception e)
{
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs
index b3a6a5da78d2..2b2f803bea88 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs
@@ -116,14 +116,14 @@ public virtual async Task DeleteAsync(CancellationToken cancellatio
///
/// Details on long running operation object.
///
- public virtual ArmOperation StartDelete(CancellationToken cancellationToken = default)
+ public virtual ArmOperation StartDelete(CancellationToken cancellationToken = default)
{
using var scope = Diagnostics.CreateScope("ResourceGroupOperations.StartDelete");
scope.Start();
try
{
- return new VoidArmOperation(Operations.StartDelete(Id.Name, cancellationToken));
+ return new PhVoidArmOperation(Operations.StartDelete(Id.Name, cancellationToken));
}
catch (Exception e)
{
@@ -140,14 +140,14 @@ public virtual ArmOperation StartDelete(CancellationToken cancellation
///
/// Details on long running operation object.
///
- public virtual async Task> StartDeleteAsync(CancellationToken cancellationToken = default)
+ public virtual async Task StartDeleteAsync(CancellationToken cancellationToken = default)
{
using var scope = Diagnostics.CreateScope("ResourceGroupOperations.StartDelete");
scope.Start();
try
{
- return new VoidArmOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false));
+ return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false));
}
catch (Exception e)
{
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs
deleted file mode 100644
index d430f210e2c1..000000000000
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-//
-
-#nullable disable
-
-using System.Collections.Generic;
-using System.Text.Json;
-using Azure.Core;
-using Azure.ResourceManager.Resources.Models;
-
-namespace Azure.ResourceManager.Core
-{
- public partial class ResourceGroupData : TrackedResource, IUtf8JsonSerializable
- {
- void IUtf8JsonSerializable.Write(Utf8JsonWriter writer)
- {
- writer.WriteStartObject();
- if (Optional.IsDefined(Properties))
- {
- writer.WritePropertyName("properties");
- writer.WriteObjectValue(Properties);
- }
- writer.WritePropertyName("location");
- writer.WriteStringValue(Location);
- if (Optional.IsDefined(ManagedBy))
- {
- writer.WritePropertyName("managedBy");
- writer.WriteStringValue(ManagedBy);
- }
- if (Optional.IsCollectionDefined(Tags))
- {
- writer.WritePropertyName("tags");
- writer.WriteStartObject();
- foreach (var item in Tags)
- {
- writer.WritePropertyName(item.Key);
- writer.WriteStringValue(item.Value);
- }
- writer.WriteEndObject();
- }
- writer.WriteEndObject();
- }
-
- internal static ResourceGroup DeserializeResourceGroup(JsonElement element)
- {
- Optional id = default;
- Optional name = default;
- Optional type = default;
- Optional properties = default;
- string location = default;
- Optional managedBy = default;
- Optional> tags = default;
- foreach (var property in element.EnumerateObject())
- {
- if (property.NameEquals("id"))
- {
- id = property.Value.GetString();
- continue;
- }
- if (property.NameEquals("name"))
- {
- name = property.Value.GetString();
- continue;
- }
- if (property.NameEquals("type"))
- {
- type = property.Value.GetString();
- continue;
- }
- if (property.NameEquals("properties"))
- {
- if (property.Value.ValueKind == JsonValueKind.Null)
- {
- property.ThrowNonNullablePropertyIsNull();
- continue;
- }
- properties = ResourceGroupProperties.DeserializeResourceGroupProperties(property.Value);
- continue;
- }
- if (property.NameEquals("location"))
- {
- location = property.Value.GetString();
- continue;
- }
- if (property.NameEquals("managedBy"))
- {
- managedBy = property.Value.GetString();
- continue;
- }
- if (property.NameEquals("tags"))
- {
- if (property.Value.ValueKind == JsonValueKind.Null)
- {
- property.ThrowNonNullablePropertyIsNull();
- continue;
- }
- Dictionary dictionary = new Dictionary();
- foreach (var property0 in property.Value.EnumerateObject())
- {
- dictionary.Add(property0.Name, property0.Value.GetString());
- }
- tags = dictionary;
- continue;
- }
- }
- return new ResourceGroupData(new Azure.ResourceManager.Resources.Models.ResourceGroup(id.Value, name.Value, type.Value, properties.Value, location, managedBy.Value, Optional.ToDictionary(tags)));
- }
- }
-}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
deleted file mode 100644
index be85a7c39829..000000000000
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.Core;
-using Azure.Core.Pipeline;
-
-namespace Azure.ResourceManager.Core
-{
- internal class UpdateResourceGroupOperation : ValueArmOperation, IOperationSource
- {
- private readonly ArmOperationHelpers _operation;
-
- public UpdateResourceGroupOperation()
- {
- }
-
- ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken)
- {
- using var document = JsonDocument.Parse(response.ContentStream);
- return ResourceGroup.DeserializeGalleryImage(document.RootElement);
- }
-
- async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken)
- {
- using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false);
- return ResourceGroup.DeserializeGalleryImage(document.RootElement);
- }
- }
-}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs
index a042dd2bc58b..f9a349a1ecd0 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs
@@ -13,7 +13,6 @@ public class ResourceTypeFilterTests
[TestCase]
public void TestResourceTypeFilterParamCheck()
{
- Assert.Throws(() => { new VoidArmOperation((Operation)null); });
Assert.Throws(() => { new VoidArmOperation((Response)null); });
}
}
From 2f90c91ac6a7b99f4db70a49d2a615573be68bba Mon Sep 17 00:00:00 2001
From: m-nash
Date: Tue, 13 Apr 2021 22:29:16 -0700
Subject: [PATCH 05/15] finalize changes before testing
---
.../UpdateResourceGroupOperation.cs | 34 ++++++----
.../src/Operation/ArmOperation.cs | 32 +++++++---
.../src/Operation/PhArmOperation.cs | 20 +++++-
.../src/Operation/PhNoValueArmOperation.cs | 35 ++++++++++
.../src/Operation/PhValueArmOperation.cs | 43 +++++++++++++
.../src/Operation/PhVoidArmOperation.cs | 35 ++++++----
.../src/Operation/ValueArmOperation.cs | 13 ----
.../src/Operation/VoidArmOperation.cs | 20 ------
.../tests/Unit/ResourceTypeFilterTests.cs | 2 +-
.../authorization/RoleAssignmentOperations.cs | 16 ++---
.../compute/AvailabilitySetOperations.cs | 16 ++---
.../compute/VirtualMachineOperations.cs | 64 +++++++++----------
.../network/NetworkInterfaceOperations.cs | 16 ++---
.../network/NetworkSecurityGroupOperations.cs | 16 ++---
.../network/PublicIpAddressOperations.cs | 16 ++---
.../Proto.Client/network/SubnetOperations.cs | 16 ++---
.../network/VirtualNetworkOperations.cs | 16 ++---
.../Proto.Client/src/Program.cs | 2 +-
18 files changed, 255 insertions(+), 157 deletions(-)
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs
create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs
delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs
delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs
index 12b58c4a8966..2cbfc34a9e13 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs
@@ -8,7 +8,7 @@
namespace Azure.ResourceManager.Core
{
- internal class UpdateResourceGroupOperation : ArmOperation, IOperationSource
+ internal class UpdateResourceGroupOperation : ArmOperation
{
private readonly ResourceOperationsBase _operations;
@@ -16,36 +16,46 @@ protected UpdateResourceGroupOperation()
{
}
+ internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Response response)
+ : base(response)
+ {
+ _operations = operations;
+ }
+
///
/// Initializes a new instance of the class.
///
- /// The operation source to use.
/// The arm operations object to copy from.
/// The original request.
- /// The original response.
- internal UpdateResourceGroupOperation(IOperationSource source, ResourceOperationsBase operations, Request request, Response response)
- : base(source, operations.Diagnostics, ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), request, response, "UpdateResourceGroupOperation")
+ /// The original response.
+ internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Request request, Response response)
+ : base(operations.Diagnostics,
+ ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions),
+ request,
+ response,
+ OperationFinalStateVia.Location,
+ "UpdateResourceGroupOperation")
{
_operations = operations;
}
- ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken)
+ public override ResourceGroup CreateResult(Response response, CancellationToken cancellationToken)
{
using var document = JsonDocument.Parse(response.ContentStream);
return GetResourceGrouop(document);
}
+ public override async ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken)
+ {
+ using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false);
+ return GetResourceGrouop(document);
+ }
+
private ResourceGroup GetResourceGrouop(JsonDocument document)
{
var method = typeof(ResourceManager.Resources.Models.ResourceGroup).GetMethod("DeserializeResourceGroup", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
var obj = method.Invoke(null, new object[] { document.RootElement });
return new ResourceGroup(_operations, new ResourceGroupData(obj as ResourceManager.Resources.Models.ResourceGroup));
}
-
- async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken)
- {
- using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false);
- return GetResourceGrouop(document);
- }
}
}
diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
index 91029ec2b479..b4ec171be1fa 100644
--- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
+++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs
@@ -12,7 +12,7 @@ namespace Azure.ResourceManager.Core
///
/// Abstract class for long-running or synchronous applications.
///
- public abstract class ArmOperation : Operation
+ public abstract class ArmOperation : Operation, IOperationSource