示例#1
0
        /// <summary>
        /// Updates PollingState from Location header on Post or Delete operations.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body.</typeparam>
        /// <typeparam name="THeader">Type of the resource header.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromLocationHeaderOnPostOrDelete <TBody, THeader>(
            IAzureClient client,
            PollingState <TBody, THeader> pollingState,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken) where TBody : class where THeader : class
        {
            AzureOperationResponse <TBody, THeader> responseWithResource = await client.GetAsync <TBody, THeader>(
                pollingState.LocationHeaderLink,
                customHeaders,
                cancellationToken).ConfigureAwait(false);

            pollingState.Response        = responseWithResource.Response;
            pollingState.Request         = responseWithResource.Request;
            pollingState.ResourceHeaders = responseWithResource.Headers;

            var statusCode = responseWithResource.Response.StatusCode;

            if (statusCode == HttpStatusCode.Accepted)
            {
                pollingState.Status = AzureAsyncOperation.InProgressStatus;
            }
            else if (statusCode == HttpStatusCode.OK ||
                     statusCode == HttpStatusCode.Created ||
                     statusCode == HttpStatusCode.NoContent)
            {
                pollingState.Status   = AzureAsyncOperation.SuccessStatus;
                pollingState.Resource = responseWithResource.Body;
            }
        }
示例#2
0
        /// <summary>
        /// Gets operation result for PUT and PATCH operations.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body</typeparam>
        /// <typeparam name="THeader">Type of the resource header</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="response">Response from the begin operation</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Response with created resource</returns>
        public static async Task <AzureOperationResponse <TBody, THeader> > GetPutOrPatchOperationResultAsync <TBody, THeader>(
            this IAzureClient client,
            AzureOperationResponse <TBody, THeader> response,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken) where TBody : class where THeader : class
        {
            if (response == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "response");
            }
            if (response.Response.StatusCode != HttpStatusCode.OK &&
                response.Response.StatusCode != HttpStatusCode.Accepted &&
                response.Response.StatusCode != HttpStatusCode.Created)
            {
                throw new CloudException(string.Format(Resources.UnexpectedPollingStatus, response.Response.StatusCode));
            }

            var pollingState    = new PollingState <TBody, THeader>(response, client.LongRunningOperationRetryTimeout);
            Uri getOperationUrl = response.Request.RequestUri;

            // Check provisioning state
            while (!AzureAsyncOperation.TerminalStatuses.Any(s => s.Equals(pollingState.Status,
                                                                           StringComparison.OrdinalIgnoreCase)))
            {
                await Task.Delay(pollingState.DelayInMilliseconds, cancellationToken).ConfigureAwait(false);

                if (!string.IsNullOrEmpty(pollingState.AzureAsyncOperationHeaderLink))
                {
                    await UpdateStateFromAzureAsyncOperationHeader(client, pollingState, customHeaders, false, cancellationToken);
                }
                else if (!string.IsNullOrEmpty(pollingState.LocationHeaderLink))
                {
                    await UpdateStateFromLocationHeaderOnPut(client, pollingState, customHeaders, cancellationToken);
                }
                else
                {
                    await UpdateStateFromGetResourceOperation(client, pollingState, getOperationUrl,
                                                              customHeaders, cancellationToken);
                }
            }

            if (AzureAsyncOperation.SuccessStatus.Equals(pollingState.Status, StringComparison.OrdinalIgnoreCase) &&
                pollingState.Resource == null)
            {
                await UpdateStateFromGetResourceOperation(client, pollingState, getOperationUrl,
                                                          customHeaders, cancellationToken);
            }

            // Check if operation failed
            if (AzureAsyncOperation.FailedStatuses.Any(
                    s => s.Equals(pollingState.Status, StringComparison.OrdinalIgnoreCase)))
            {
                throw pollingState.CloudException;
            }

            return(pollingState.AzureOperationResponse);
        }
示例#3
0
        /// <summary>
        /// Updates PollingState from Location header on Put operations.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body.</typeparam>
        /// <typeparam name="THeader">Type of the resource header.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromLocationHeaderOnPut <TBody, THeader>(
            IAzureClient client,
            PollingState <TBody, THeader> pollingState,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken) where TBody : class where THeader : class
        {
            AzureOperationResponse <JObject, JObject> responseWithResource = await client.GetRawAsync(
                pollingState.LocationHeaderLink,
                customHeaders,
                cancellationToken).ConfigureAwait(false);

            pollingState.Response = responseWithResource.Response;
            pollingState.Request  = responseWithResource.Request;

            var statusCode = responseWithResource.Response.StatusCode;

            if (statusCode == HttpStatusCode.Accepted)
            {
                pollingState.Status = AzureAsyncOperation.InProgressStatus;
            }
            else if (statusCode == HttpStatusCode.OK ||
                     statusCode == HttpStatusCode.Created)
            {
                if (responseWithResource.Body == null)
                {
                    throw new CloudException(Resources.NoBody);
                }

                // In 202 pattern on PUT ProvisioningState may not be present in
                // the response. In that case the assumption is the status is Succeeded.
                var resource = responseWithResource.Body;
                if (resource["properties"] != null && resource["properties"]["provisioningState"] != null)
                {
                    pollingState.Status = (string)resource["properties"]["provisioningState"];
                }
                else
                {
                    pollingState.Status = AzureAsyncOperation.SuccessStatus;
                }

                pollingState.Error = new CloudError()
                {
                    Code    = pollingState.Status,
                    Message = string.Format(Resources.LongRunningOperationFailed, pollingState.Status)
                };
                pollingState.Resource = responseWithResource.Body.ToObject <TBody>(JsonSerializer
                                                                                   .Create(client.DeserializationSettings));
                pollingState.ResourceHeaders = responseWithResource.Headers.ToObject <THeader>(JsonSerializer
                                                                                               .Create(client.DeserializationSettings));
            }
        }
        /// <summary>
        /// Updates PollingState from Azure-AsyncOperation header.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body.</typeparam>
        /// <typeparam name="THeader">Type of the resource header.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromAzureAsyncOperationHeader <TBody, THeader>(
            IAzureClient client,
            PollingState <TBody, THeader> pollingState,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken,
            HttpMethod initialRequestMethod) where TBody : class where THeader : class
        {
            string errMessage = string.Empty;

            AzureOperationResponse <AzureAsyncOperation, object> asyncOperationResponse =
                await client.GetAsync <AzureAsyncOperation, object>(
                    pollingState.AzureAsyncOperationHeaderLink,
                    customHeaders,
                    cancellationToken).ConfigureAwait(false);

            if (asyncOperationResponse.Body == null || asyncOperationResponse.Body.Status == null)
            {
                throw new CloudException(Resources.NoBody);
            }

            string responseContent = await asyncOperationResponse.Response.Content.ReadAsStringAsync().ConfigureAwait(false);

            pollingState.Response = asyncOperationResponse.Response;
            pollingState.Request  = asyncOperationResponse.Request;
            pollingState.Resource = null;
            pollingState.Status   = asyncOperationResponse.Body.Status;

            // In LRO with async operation header, we only update polling state if the status is one of the failed one
            if (AzureAsyncOperation.FailedStatuses.Any(
                    s => s.Equals(pollingState.Status, StringComparison.OrdinalIgnoreCase)))
            {
                //As this is for AsyncOperation header, we pass AzureOperationResponse as null
                pollingState = GetUpdatedPollingStatus <TBody, THeader>(asyncOperationResponse.Body,
                                                                        null, pollingState, responseContent, initialRequestMethod);
            }

            //Try to de-serialize to the response model. (Not required for "PutOrPatch"
            //which has the fallback of invoking generic "resource get".)
            var responseHeaders = pollingState.Response.Headers.ToJson();

            try
            {
                pollingState.Resource = JObject.Parse(responseContent)
                                        .ToObject <TBody>(JsonSerializer.Create(client.DeserializationSettings));
                pollingState.ResourceHeaders =
                    responseHeaders.ToObject <THeader>(JsonSerializer.Create(client.DeserializationSettings));
            }
            catch { };
        }
        /// <summary>
        /// Updates PollingState from GET operations.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body.</typeparam>
        /// <typeparam name="THeader">Type of the resource header.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="getOperationUri">Uri for the get operation</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromGetResourceOperation <TBody, THeader>(
            IAzureClient client,
            PollingState <TBody, THeader> pollingState,
            Uri getOperationUri,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken,
            HttpMethod initialRequestMethod) where TBody : class where THeader : class
        {
            AzureAsyncOperation asyncOperation = null;

            AzureOperationResponse <JObject, JObject> responseWithResource = await GetRawAsync(client,
                                                                                               getOperationUri.AbsoluteUri, customHeaders, cancellationToken).ConfigureAwait(false);

            if (responseWithResource.Body == null)
            {
                throw new CloudException(Resources.NoBody);
            }

            string responseContent = await responseWithResource.Response.Content.ReadAsStringAsync().ConfigureAwait(false);

            pollingState.Response = responseWithResource.Response;
            pollingState.Request  = responseWithResource.Request;
            pollingState.Resource = responseWithResource.Body.ToObject <TBody>(JsonSerializer
                                                                               .Create(client.DeserializationSettings));
            pollingState.ResourceHeaders = responseWithResource.Headers.ToObject <THeader>(JsonSerializer
                                                                                           .Create(client.DeserializationSettings));

            // In 202 pattern on PUT ProvisioningState may not be present in
            // the response. In that case the assumption is the status is Succeeded.

            // We try to check if the response had status/error returned
            // the reason we deserialize it as AsyncOperation is simply because we are trying to reuse the AsyncOperation model for deserialization (which has Error, Code and Message model types)
            // which is how the response is returned
            // Ideally the response body should be provided as a type TBody, but TBody is a type defined in the swagger and so we cannot provide that type in the constraint hence we end up using a generic
            // JBody type
            try
            {
                asyncOperation = responseWithResource.Body.ToObject <AzureAsyncOperation>(JsonSerializer.Create(client.DeserializationSettings));
            }
            catch { }

            pollingState = GetUpdatedPollingStatus <TBody, THeader>(asyncOperation, responseWithResource, pollingState, responseContent, initialRequestMethod);
        }
示例#6
0
        /// <summary>
        /// Updates PollingState from Location header.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body.</typeparam>
        /// <typeparam name="THeader">Type of the resource header.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <param name="method">Http method of the initial long running operation request</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromLocationHeader <TBody, THeader>(
            IAzureClient client,
            PollingState <TBody, THeader> pollingState,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken,
            HttpMethod method) where TBody : class where THeader : class
        {
            AzureOperationResponse <JObject, JObject> responseWithResource = await client.GetRawAsync(
                pollingState.LocationHeaderLink,
                customHeaders,
                cancellationToken).ConfigureAwait(false);

            pollingState.Response = responseWithResource.Response;
            pollingState.Request  = responseWithResource.Request;

            var statusCode = responseWithResource.Response.StatusCode;

            if (statusCode == HttpStatusCode.Accepted)
            {
                pollingState.Status = AzureAsyncOperation.InProgressStatus;
            }
            else if (statusCode == HttpStatusCode.OK ||
                     (statusCode == HttpStatusCode.Created && method == HttpMethod.Put) ||
                     (statusCode == HttpStatusCode.NoContent && (method == HttpMethod.Delete || method == HttpMethod.Post)))
            {
                pollingState.Status = AzureAsyncOperation.SuccessStatus;

                pollingState.Error = new CloudError()
                {
                    Code    = pollingState.Status,
                    Message = string.Format(Resources.LongRunningOperationFailed, pollingState.Status)
                };
                pollingState.Resource = responseWithResource.Body == null ? null : responseWithResource.Body.ToObject <TBody>(JsonSerializer
                                                                                                                              .Create(client.DeserializationSettings));
                pollingState.ResourceHeaders = responseWithResource.Headers.ToObject <THeader>(JsonSerializer
                                                                                               .Create(client.DeserializationSettings));
            }
            else
            {
                throw new CloudException("The response from long running operation does not have a valid status code.");
            }
        }
示例#7
0
        /// <summary>
        /// Updates PollingState from Azure-AsyncOperation header.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body.</typeparam>
        /// <typeparam name="THeader">Type of the resource header.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="postOrDelete">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromAzureAsyncOperationHeader <TBody, THeader>(
            IAzureClient client,
            PollingState <TBody, THeader> pollingState,
            Dictionary <string, List <string> > customHeaders,
            bool postOrDelete,
            CancellationToken cancellationToken) where TBody : class where THeader : class
        {
            AzureOperationResponse <AzureAsyncOperation, object> asyncOperationResponse =
                await client.GetAsync <AzureAsyncOperation, object>(
                    pollingState.AzureAsyncOperationHeaderLink,
                    customHeaders,
                    cancellationToken).ConfigureAwait(false);

            if (asyncOperationResponse.Body == null || asyncOperationResponse.Body.Status == null)
            {
                throw new CloudException(Resources.NoBody);
            }

            pollingState.Status   = asyncOperationResponse.Body.Status;
            pollingState.Error    = asyncOperationResponse.Body.Error;
            pollingState.Response = asyncOperationResponse.Response;
            pollingState.Request  = asyncOperationResponse.Request;
            pollingState.Resource = null;
            if (postOrDelete)
            {
                //Try to de-serialize to the response model. (Not required for "PutOrPatch"
                //which has the fallback of invoking generic "resource get".)
                string responseContent = await pollingState.Response.Content.ReadAsStringAsync();

                var responseHeaders = pollingState.Response.Headers.ToJson();
                try
                {
                    pollingState.Resource = JObject.Parse(responseContent)
                                            .ToObject <TBody>(JsonSerializer.Create(client.DeserializationSettings));
                    pollingState.ResourceHeaders =
                        responseHeaders.ToObject <THeader>(JsonSerializer.Create(client.DeserializationSettings));
                }
                catch { };
            }
        }
示例#8
0
        /// <summary>
        /// Updates PollingState from GET operations.
        /// </summary>
        /// <typeparam name="T">Type of the resource.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="getOperationUri">Uri for the get operation</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromGetResourceOperation <T>(
            IAzureClient client,
            PollingState <T> pollingState,
            Uri getOperationUri,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken)
            where T : class
        {
            AzureOperationResponse <JObject> responseWithResource = await GetRawAsync(client,
                                                                                      getOperationUri.AbsoluteUri, customHeaders, cancellationToken).ConfigureAwait(false);

            if (responseWithResource.Body == null)
            {
                throw new CloudException(Resources.NoBody);
            }

            // In 202 pattern on PUT ProvisioningState may not be present in
            // the response. In that case the assumption is the status is Succeeded.
            var resource = responseWithResource.Body;

            if (resource["properties"] != null && resource["properties"]["provisioningState"] != null)
            {
                pollingState.Status = (string)resource["properties"]["provisioningState"];
            }
            else
            {
                pollingState.Status = AzureAsyncOperation.SuccessStatus;
            }

            pollingState.Error = new CloudError()
            {
                Code    = pollingState.Status,
                Message = string.Format(Resources.LongRunningOperationFailed, pollingState.Status)
            };
            pollingState.Response = responseWithResource.Response;
            pollingState.Request  = responseWithResource.Request;
            pollingState.Resource = responseWithResource.Body.ToObject <T>(JsonSerializer
                                                                           .Create(client.DeserializationSettings));
        }
        /// <summary>
        /// Updates PollingState from Azure-AsyncOperation header.
        /// </summary>
        /// <typeparam name="T">Type of the resource.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Task.</returns>
        private static async Task  UpdateStateFromAzureAsyncOperationHeader <T>(
            IAzureClient client,
            PollingState <T> pollingState,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken)
            where T : class
        {
            var asyncOperationResponse = await client.GetAsync <AzureAsyncOperation>(
                pollingState.AzureAsyncOperationHeaderLink,
                customHeaders,
                cancellationToken).ConfigureAwait(false);

            if (asyncOperationResponse.Body == null || asyncOperationResponse.Body.Status == null)
            {
                throw new CloudException(Resources.NoBody);
            }

            pollingState.Status   = asyncOperationResponse.Body.Status;
            pollingState.Error    = asyncOperationResponse.Body.Error;
            pollingState.Response = asyncOperationResponse.Response;
            pollingState.Request  = asyncOperationResponse.Request;
            pollingState.Resource = null;
        }
        /// <summary>
        /// Updates PollingState from Location header.
        /// </summary>
        /// <typeparam name="TBody">Type of the resource body.</typeparam>
        /// <typeparam name="THeader">Type of the resource header.</typeparam>
        /// <param name="client">IAzureClient</param>
        /// <param name="pollingState">Current polling state.</param>
        /// <param name="customHeaders">Headers that will be added to request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <param name="initialRequestMethod">Http method of the initial long running operation request</param>
        /// <returns>Task.</returns>
        private static async Task UpdateStateFromLocationHeader <TBody, THeader>(
            IAzureClient client,
            PollingState <TBody, THeader> pollingState,
            Dictionary <string, List <string> > customHeaders,
            CancellationToken cancellationToken,
            HttpMethod initialRequestMethod) where TBody : class where THeader : class
        {
            AzureAsyncOperation asyncOperation = null;

            AzureOperationResponse <JObject, JObject> responseWithResource = await client.GetRawAsync(
                pollingState.LocationHeaderLink,
                customHeaders,
                cancellationToken).ConfigureAwait(false);

            string responseContent = await responseWithResource.Response.Content.ReadAsStringAsync().ConfigureAwait(false);

            pollingState.Status   = responseWithResource.Response.StatusCode.ToString();
            pollingState.Response = responseWithResource.Response;
            pollingState.Request  = responseWithResource.Request;
            pollingState.Resource = responseWithResource.Body == null ? null : responseWithResource.Body.ToObject <TBody>(JsonSerializer
                                                                                                                          .Create(client.DeserializationSettings));
            pollingState.ResourceHeaders = responseWithResource.Headers.ToObject <THeader>(JsonSerializer
                                                                                           .Create(client.DeserializationSettings));

            // We try to check if the response had status/error returned
            // the reason we deserialize it as AsyncOperation is simply because we are trying to reuse the AsyncOperation model for deserialization (which has Error, Code and Message model types)
            // which is how the response is returned
            // Ideally the response body should be provided as a type TBody, but TBody is a type defined in the swagger and so we cannot provide that type in the constraint hence we end up using a generic
            // JBody type
            try
            {
                asyncOperation = responseWithResource.Body.ToObject <AzureAsyncOperation>(JsonSerializer.Create(client.DeserializationSettings));
            }
            catch { }

            pollingState = GetUpdatedPollingStatus <TBody, THeader>(asyncOperation, responseWithResource, pollingState, responseContent, initialRequestMethod);
        }
        /// <summary>
        /// The primary purpose for this function is to get status and if there is any error
        /// Update error information to pollingState.Error and pollingState.Exception
        ///
        /// We have on a very high level two cases
        /// 1) Regardless what kind of LRO operation it is (AzureAsync, locaiton header) either we get error or we dont
        /// 2) If we get error object, this function expects that information in the form of AzureAsyncOperation model type
        /// 3) We get status and error information from AzureAsyncOperation modele and update PollingState accordingly.
        /// 3) If AzureAsyncOperation is null, we assume there was no error retruned in the response
        /// 4) And we get the status from provisioningState and update pollingState accordinly
        /// </summary>
        /// <typeparam name="TBody"></typeparam>
        /// <typeparam name="THeader"></typeparam>
        /// <param name="asyncOperation"></param>
        /// <param name="azureResponse"></param>
        /// <param name="pollState"></param>
        /// <param name="responseContent"></param>
        /// <param name="initialRequestMethod"></param>
        /// <returns></returns>
        private static PollingState <TBody, THeader> GetUpdatedPollingStatus <TBody, THeader>(
            AzureAsyncOperation asyncOperation,
            AzureOperationResponse <JObject, JObject> azureResponse,
            PollingState <TBody, THeader> pollState,
            string responseContent,
            HttpMethod initialRequestMethod)
            where TBody : class
            where THeader : class
        {
            PollingState <TBody, THeader> pollingState = pollState;
            HttpStatusCode statusCode;

            // We are only interested if we see the status as one of the failed states and we have a valid error body
            if (AzureAsyncOperation.FailedStatuses.Any(
                    s => s.Equals(pollingState.Status, StringComparison.OrdinalIgnoreCase)))
            {
                if (asyncOperation?.Error == null)
                {
                    // we need this check until service teams starts implementing v2.2 Azure REST API guidlines, when error will be mandatory on Failed/Canceled status
                    // in Az async operation, it's not madatory currently to send error body on failed/cancelled status
                    if (string.IsNullOrEmpty(pollingState.AzureAsyncOperationHeaderLink))
                    {
                        asyncOperation = null;
                    }
                    //else
                    //{
                    //    // there is no error body, so asynOperation is of no use for us at this stage, we will continue analyzing the response and try to find provisioning state etc
                    //    asyncOperation = null;
                    //}
                }
            }
            else
            {
                // also if the status is a non-standard terminal states (RP provided state e.g. TestFailed, TestSucceeded etc)
                // we again assume this is a response that RP provided for their LRO will continue analyzing the response accordingly
                asyncOperation = null;
            }


            if (asyncOperation != null)
            {
                string errorMessage = string.Empty;
                string errorCode    = string.Empty;

                pollingState.Status = asyncOperation.Status;

                if (asyncOperation?.Error == null)
                {
                    errorMessage = string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.LongRunningOperationFailed,
                        asyncOperation.Status);
                }
                else
                {
                    errorMessage = string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.LROOperationFailedAdditionalInfo,
                        asyncOperation.Status, asyncOperation.Error?.Message);
                    errorCode = asyncOperation.Error.Code;
                }

                pollingState.Error = new CloudError()
                {
                    Code    = errorCode,
                    Message = errorMessage
                };

                pollingState.CloudException = new CloudException(errorMessage)
                {
                    Body     = asyncOperation?.Error,
                    Request  = new HttpRequestMessageWrapper(pollingState.Request, null),
                    Response = new HttpResponseMessageWrapper(pollingState.Response, responseContent)
                };
            }
            else if (azureResponse != null)
            {
                statusCode = azureResponse.Response.StatusCode;
                var resource = azureResponse.Body;

                if (statusCode == HttpStatusCode.Accepted)
                {
                    pollingState.Status = AzureAsyncOperation.InProgressStatus;
                }
                else if (statusCode == HttpStatusCode.OK ||
                         (statusCode == HttpStatusCode.Created && initialRequestMethod == HttpMethod.Put) ||
                         (statusCode == HttpStatusCode.NoContent && (initialRequestMethod == HttpMethod.Delete || initialRequestMethod == HttpMethod.Post)))
                {
                    // We check if we got provisionState and we get the status from provisioning state

                    // In 202 pattern on PUT ProvisioningState may not be present in
                    // the response. In that case the assumption is the status is Succeeded.
                    if (resource != null &&
                        resource["properties"] != null &&
                        resource["properties"]["provisioningState"] != null)
                    {
                        pollingState.Status = (string)resource["properties"]["provisioningState"];
                    }
                    else
                    {
                        pollingState.Status = AzureAsyncOperation.SuccessStatus;
                    }
                }
                else
                {
                    throw new CloudException("The response from long running operation does not have a valid status code.");
                }
            }
            else
            {
                throw new CloudException("The response from long running operation does not have a valid status code.");
            }

            return(pollingState);
        }
        private static async Task <AzureOperationResponse <TBody, THeader> > LegacyLro <TBody, THeader>(IAzureClient client,
                                                                                                        AzureOperationResponse <TBody, THeader> response,
                                                                                                        Dictionary <string, List <string> > customHeaders,
                                                                                                        CancellationToken cancellationToken)
            where TBody : class where THeader : class
        {
            if (response == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "response");
            }

            if (response.Response == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "response.Response");
            }

            if (response.Request == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "response.Request");
            }

            if (response.Request.Method == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "response.Request.Method");
            }

            var initialRequestMethod = response.Request.Method;

            if (CheckResponseStatusCodeFailed(response))
            {
                throw new CloudException(string.Format(
                                             Resources.UnexpectedPollingStatus,
                                             response.Response.StatusCode,
                                             initialRequestMethod));
            }

            var pollingState    = new PollingState <TBody, THeader>(response, client.LongRunningOperationRetryTimeout);
            Uri getOperationUrl = response.Request.RequestUri;

            // Check provisioning state
            while (!AzureAsyncOperation.TerminalStatuses.Any(s => s.Equals(pollingState.Status,
                                                                           StringComparison.OrdinalIgnoreCase)))
            {
                await Task.Delay(pollingState.DelayBetweenPolling, cancellationToken).ConfigureAwait(false);

                if (!string.IsNullOrEmpty(pollingState.AzureAsyncOperationHeaderLink))
                {
                    await UpdateStateFromAzureAsyncOperationHeader(client, pollingState, customHeaders, cancellationToken, initialRequestMethod).ConfigureAwait(false);
                }
                else if (!string.IsNullOrEmpty(pollingState.LocationHeaderLink))
                {
                    await UpdateStateFromLocationHeader(client, pollingState, customHeaders, cancellationToken, initialRequestMethod).ConfigureAwait(false);
                }
                else if (initialRequestMethod == HttpMethod.Put)
                {
                    await UpdateStateFromGetResourceOperation(client, pollingState, getOperationUrl,
                                                              customHeaders, cancellationToken, initialRequestMethod).ConfigureAwait(false);
                }
                else
                {
                    throw new CloudException("Location header is missing from long running operation.");
                }
            }

            if (AzureAsyncOperation.SuccessStatus.Equals(pollingState.Status, StringComparison.OrdinalIgnoreCase))
            {
                if ((!string.IsNullOrEmpty(pollingState.AzureAsyncOperationHeaderLink) || pollingState.Resource == null) &&
                    (initialRequestMethod == HttpMethod.Put || initialRequestMethod == new HttpMethod("PATCH")))
                {
                    await UpdateStateFromGetResourceOperation(client, pollingState, getOperationUrl, customHeaders,
                                                              cancellationToken, initialRequestMethod);
                }
            }

            // Check if operation failed
            if (AzureAsyncOperation.FailedStatuses.Any(
                    s => s.Equals(pollingState.Status, StringComparison.OrdinalIgnoreCase)))
            {
                throw pollingState.CloudException;
            }

            return(pollingState.AzureOperationResponse);
        }