/// <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; } }
/// <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); }
/// <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); }
/// <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."); } }
/// <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 { }; } }
/// <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); }