Exporter (0) Imprimer
Développer tout

Obtenir l'état de l'opération

Mis à jour: septembre 2014

L'opération Get Operation Status retourne l'état actuel de l'opération de passerelle spécifiée. Après avoir appelé une opération asynchrone, vous pouvez appeler Get Operation Status pour déterminer si l'opération est terminée, a échoué, ou est encore en cours.

La requête Get Operation Status peut être spécifiée comme suit. Remplacez <subscription-id> par l'ID d'abonnement et <request-id> par l'ID de demande qui a été renvoyé dans une réponse.

 

Méthode URI de demande

GET

https://management.core.windows.net/<subscription-id>/operations/<request-id>

Vous devez vous assurer que la demande adressée au service de gestion est sécurisée. Pour plus de détails, consultez Authentification des demandes de gestion des services.

Le tableau suivant décrit les en-têtes de la demande.

 

En-tête de demande Description

x-ms-version

Obligatoire. Spécifie la version de l'opération à utiliser pour cette demande. Cet en-tête devrait être défini sur 01/10/2009 ou une version ultérieure. Pour plus d'informations sur les en-têtes du suivi de version, consultez Contrôle de version du service de gestion.

La réponse inclut un code d'état HTTP, un ensemble d'en-têtes de réponse et un corps de réponse.

Une opération ayant réussi retourne le code d'état 200 (OK). Pour plus d'informations sur les codes d'état, consultez Codes d'état et d'erreur de la gestion des services.

La réponse de l'opération inclut les en-têtes suivants. La réponse peut aussi inclure des en-têtes HTTP standard supplémentaires. Tous les en-têtes standard sont conformes à la spécification du protocole HTTP/1.1.

 

En-tête de réponse Description

x-ms-request-id

Valeur qui identifie de façon unique une demande effectuée au service de gestion.

Le corps de la réponse contient l'état de l'opération asynchrone spécifiée, indiquant si elle a réussi, si elle est en cours, ou si elle a échoué. Cet état est distinct du code d'état HTTP renvoyé pour l'opération Get Operation Status elle-même.

Si l'opération asynchrone réussit, le corps de la réponse inclut le code d'état HTTP indiquant que la demande a réussi.

Si l'opération asynchrone échoue, le corps de la réponse inclut un code d'état HTTP indiquant que la demande a échoué, et comprend également les informations d'erreur concernant l'échec.


<?xml version="1.0" encoding="utf-8"?>
  <Operation xmlns="http://schemas.microsoft.com/windowsazure">
    <ID>request-id</ID>
    <Status>InProgress|Succeeded|Failed</Status>
    <!--Response includes HTTP status code only if the operation succeeded or failed -->
    <HttpStatusCode>http-status-code-for-asynchronous-operation</HttpStatusCode>
    <!--Response includes additional error information only if the operation failed -->
    <Error>
      <Code>error-code</Code>
      <Message>error-message</Message>
    </Error>
  </Operation>

Le tableau suivant décrit les éléments dans le corps de la réponse.

 

Nom de l'élément Description

ID

Spécifie l'ID de demande de la demande asynchrone. Cette valeur est retournée dans l'en-tête de réponse x-ms-request-id de la demande asynchrone.

État

Spécifie l'état de la demande asynchrone.

Les valeurs possibles sont les suivantes :

  • InProgress

  • Succeeded

  • Failed

HttpStatusCode

Spécifie le code d'état HTTP pour la demande asynchrone.

Code

Spécifie le code d'erreur du service de gestion renvoyé si la demande asynchrone échoue. Pour plus d'informations sur les codes d'erreur qui peuvent être retournés par le service, consultez Codes d'état et d'erreur de la gestion des services.

Message

Spécifie le message d'erreur du service de gestion renvoyé si la demande asynchrone échoue.

Les opérations de gestion du service qui nécessitent un traitement prolongé sont implémentées avec un modèle asynchrone. Toutes les demandes réussies de l'opération d'API REST de gestion des services renvoient un seul ID de demande, qui peut être utilisé pour déterminer la situation finale d'une opération. Cette opération s'effectue en interrogeant Get Operation Status avec l'ID de la demande jusqu'à ce que l'opération ait réussi ou échoué. Une demande d'opération asynchrone de gestion des services renvoie rapidement une réponse. Une réponse d'erreur à la demande d'opération asynchrone indique que la demande n'a pas abouti et qu'aucune opération asynchrone n'est en attente. Une demande d'opération renvoie le code d'état 202 (Accepté) pour indiquer que la demande a été effectuée avec succès et est en attente. L'opération Get Operation Status retournera un code d'état d'erreur et un corps de réponse d'erreur si l'appel à Get Operation Status ne réussit pas, par exemple, si l'ID de demande ne correspond à aucune demande réelle d'opération de gestion des services sur votre abonnement. Le code d'état 200 (OK) indique que l'appel Get Operation Status a été passé correctement, et que l'état de l'opération spécifiée par le paramètre d'ID de demande est stocké dans le corps de la réponse retournée. Vous devez vérifier l'état de l'opération asynchrone dans le corps de la réponse. L'élément Operation ou le corps de la réponse contient une valeur d'élément Status qui représente l'état actuel de l'opération en attente, pouvant être InProgress, Failed, ou Succeeded. Continuez à interroger l'élément Get Operation Status tant que l'élément Status contient InProgress. Lorsque l'élément Status a la valeur Succeeded ou Failed, l'élément Operation contient également un élément HttpStatusCode contenant le code d'état de l'opération asynchrone terminée. Si l'élément Status contient Failed, l'élément Operation contient un élément Error avec Code et les éléments Message fournissent des informations sur l'erreur de l'opération asynchrone.

Cet exemple de programme de console crée un nouveau compte de stockage, définissant la description, l'étiquette et l'emplacement avec l'opération Créer un compte de stockage, puis interroge l'opération Get Operation Status avec l'ID de demande retourné de l'opération Créer un compte de stockage jusqu'à ce que l'appel ait réussi, ou échoué, ou jusqu'à ce que l'interrogation ait expiré. Enfin, il appelle Obtenir les propriétés du compte de stockage pour afficher les propriétés du nouveau compte de stockage. Définissez la valeur pour l'en-tête x-ms-version dans la chaîne Version, votre identificateur d'abonnement dans SubscriptionId, votre empreinte numérique de certificat de gestion dans Thumbprint, et définissez ServiceName sur un nom de compte de stockage unique pour exécuter l'exemple.

namespace Microsoft.WindowsAzure.ServiceManagementRESTAPI.Samples
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    using System.Threading;
    using System.Xml;
    using System.Xml.Linq;
 
    public class Program
    {
        // Set these constants with your values to run the sample.
        private const string Version = "2011-10-01";
        private const string Thumbprint = "management-certificate-thumbprint";
        private const string SubscriptionId = "subscription-identifier";
        private const string ServiceName = "unique-storage-account-name";
 
        // This is the common namespace for all Service Management REST API XML data.
        private static XNamespace wa = "http://schemas.microsoft.com/windowsazure";
 
        /// <summary>
        /// The operation status values from PollGetOperationStatus.
        /// </summary>
        private enum OperationStatus
        {
            InProgress,
            Failed,
            Succeeded,
            TimedOut
        }
 
        /// <summary>
        /// Gets or sets the certificate that matches the Thumbprint value.
        /// </summary>
        private static X509Certificate2 Certificate { getset; }
 
        static void Main(string[] args)
        {
            try
            {
                Certificate = GetCertificate(Thumbprint);
 
                // Create the new storage account with the following values:
                string description = "Description for my example storage account";
                string label = "My example storage account label";
                string location = "North Central US";
                string requestId = CreateStorageAccount(
                    ServiceName, 
                    description, 
                    label, 
                    null, 
                    location);
                Console.WriteLine(
                    "Called Create Storage Account operation: requestId {0}",
                    requestId);
 
                // Loop on Get Operation Status for result of storage creation
                OperationResult result = PollGetOperationStatus(
                    requestId, 
                    pollIntervalSeconds: 20,
                    timeoutSeconds: 180);
                switch (result.Status)
                {
                    case OperationStatus.TimedOut:
                        Console.WriteLine(
                            "Poll of Get Operation Status timed out: " +
                            "Operation {0} is still in progress after {1} seconds.",
                            requestId, 
                            (int)result.RunningTime.TotalSeconds);
                        break;
 
                    case OperationStatus.Failed:
                        Console.WriteLine(
                            "Failed: Operation {0} failed after " + 
                            "{1} seconds with status {2} ({3}) - {4}: {5}",
                            requestId, 
                            (int)result.RunningTime.TotalSeconds,
                            (int)result.StatusCode, 
                            result.StatusCode, 
                            result.Code, 
                            result.Message);
                        break;
 
                    case OperationStatus.Succeeded:
                        Console.WriteLine(
                            "Succeeded: Operation {0} completed " +
                            "after {1} seconds with status {2} ({3})",
                            requestId, 
                            (int)result.RunningTime.TotalSeconds, 
                            (int)result.StatusCode, 
                            result.StatusCode);
                        break;
                }
 
                // Display the property values for the new storage account.
                // Convert the Label property to a readable value for display.
                XElement updatedProperties =
                    GetStorageAccountProperties(ServiceName);
                XElement labelElement = updatedProperties.Descendants(wa + "Label").First();
                labelElement.Value = labelElement.Value.FromBase64();
                Console.WriteLine(
                    "New Storage Account Properties for {0}:{1}{2}",
                    ServiceName,
                    Environment.NewLine,
                    updatedProperties.ToString(SaveOptions.OmitDuplicateNamespaces));
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception caught in Main:");
                Console.WriteLine(ex.Message);
            }
 
            Console.Write("Press any key to continue:");
            Console.ReadKey();
        }
 
        /// <summary>
        /// Calls the Get Storage Account Properties operation in the Service 
        /// Management REST API for the specified subscription and storage account 
        /// name and returns the StorageService XML element from the response.
        /// </summary>
        /// <param name="serviceName">The name of the storage account.</param>
        /// <returns>The StorageService XML element from the response.</returns>
        private static XElement GetStorageAccountProperties(
            string serviceName)
        {
            string uriFormat = "https://management.core.windows.net/{0}" +
                "/services/storageservices/{1}";
            Uri uri = new Uri(String.Format(uriFormat, SubscriptionId, serviceName));
            XDocument responseBody;
            InvokeRequest(uri, "GET", HttpStatusCode.OK, nullout responseBody);
            return responseBody.Element(wa + "StorageService");
        }
 
        /// <summary>
        /// Calls the Create Storage Account operation in the Service Management 
        /// REST API for the specified subscription, storage account name, 
        /// description, label, and location or affinity group.
        /// </summary>
        /// <param name="serviceName">The name of the storage account to update.</param>
        /// <param name="description">The new description for the storage account.</param>
        /// <param name="label">The new label for the storage account.</param>
        /// <param name="affinityGroup">The affinity group name, or null to use a location.</param>
        /// <param name="location">The location name, or null to use an affinity group.</param>
        /// <returns>The requestId for the operation.</returns>
        private static string CreateStorageAccount(
            string serviceName,
            string description,
            string label,
            string affinityGroup,
            string location)
        {
            string uriFormat = "https://management.core.windows.net/{0}" +
                "/services/storageservices";
            Uri uri = new Uri(String.Format(uriFormat, SubscriptionId));
 
            // Location and Affinity Group are mutually exclusive. 
            // Use the location if it isn't null or empty.
            XElement locationOrAffinityGroup = String.IsNullOrEmpty(location) ?
                new XElement(wa + "AffinityGroup", affinityGroup) :
                new XElement(wa + "Location", location);
 
            // Create the request XML document
            XDocument requestBody = new XDocument(
                new XDeclaration("1.0""UTF-8""no"),
                new XElement(
                    wa + "CreateStorageServiceInput",
                    new XElement(wa + "ServiceName", serviceName),
                    new XElement(wa + "Description", description),
                    new XElement(wa + "Label", label.ToBase64()),
                    locationOrAffinityGroup));
 
            XDocument responseBody;
            return InvokeRequest(
                uri, "POST", HttpStatusCode.Accepted, requestBody, out responseBody);
        }
 
        /// <summary>
        /// Calls the Get Operation Status operation in the Service 
        /// Management REST API for the specified subscription and requestId 
        /// and returns the Operation XML element from the response.
        /// </summary>
        /// <param name="requestId">The requestId of the operation to track.</param>
        /// <returns>The Operation XML element from the response.</returns>
        private static XElement GetOperationStatus(
            string requestId)
        {
            string uriFormat = "https://management.core.windows.net/{0}" +
                "/operations/{1}";
            Uri uri = new Uri(String.Format(uriFormat, SubscriptionId, requestId));
            XDocument responseBody;
            InvokeRequest(uri, "GET", HttpStatusCode.OK, nullout responseBody);
            return responseBody.Element(wa + "Operation");
        }
 
        /// <summary>
        /// The results from PollGetOperationStatus are passed in this struct.
        /// </summary>
        private struct OperationResult
        {
            // The status: InProgress, Failed, Succeeded, or TimedOut.
            public OperationStatus Status { getset; }
 
            // The http status code of the requestId operation, if any.
            public HttpStatusCode StatusCode { getset; }
 
            // The approximate running time for PollGetOperationStatus.
            public TimeSpan RunningTime { getset; }
 
            // The error code for the failed operation.
            public string Code { getset; }
 
            // The message for the failed operation.
            public string Message { getset; }
        }
 
        /// <summary>
        /// Polls Get Operation Status for the operation specified by requestId
        /// every pollIntervalSeconds until timeoutSeconds have passed or the
        /// operation has returned a Failed or Succeeded status. 
        /// </summary>
        /// <param name="requestId">The requestId of the operation to get status for.</param>
        /// <param name="pollIntervalSeconds">The interval between calls to Get Operation Status.</param>
        /// <param name="timeoutSeconds">The maximum number of seconds to poll.</param>
        /// <returns>An OperationResult structure with status or error information.</returns>
        private static OperationResult PollGetOperationStatus(
            string requestId,
            int pollIntervalSeconds,
            int timeoutSeconds)
        {
            OperationResult result = new OperationResult();
            DateTime beginPollTime = DateTime.UtcNow;
            TimeSpan pollInterval = new TimeSpan(0, 0, pollIntervalSeconds);
            DateTime endPollTime = beginPollTime + new TimeSpan(0, 0, timeoutSeconds);
 
            bool done = false;
            while (!done)
            {
                XElement operation = GetOperationStatus(requestId);
                result.RunningTime = DateTime.UtcNow - beginPollTime;
                try
                {
                    // Turn the Status string into an OperationStatus value
                    result.Status = (OperationStatus)Enum.Parse(
                        typeof(OperationStatus),
                        operation.Element(wa + "Status").Value);
                }
                catch (Exception)
                {
                    throw new ApplicationException(string.Format(
                        "Get Operation Status {0} returned unexpected status: {1}{2}",
                        requestId,
                        Environment.NewLine,
                        operation.ToString(SaveOptions.OmitDuplicateNamespaces)));
                }
 
                switch (result.Status)
                {
                    case OperationStatus.InProgress:
                        Console.WriteLine(
                            "In progress for {0} seconds", 
                            (int)result.RunningTime.TotalSeconds);
                        Thread.Sleep((int)pollInterval.TotalMilliseconds);
                        break;
 
                    case OperationStatus.Failed:
                        result.StatusCode = (HttpStatusCode)Convert.ToInt32(
                            operation.Element(wa + "HttpStatusCode").Value);
                        XElement error = operation.Element(wa + "Error");
                        result.Code = error.Element(wa + "Code").Value;
                        result.Message = error.Element(wa + "Message").Value;
                        done = true;
                        break;
 
                    case OperationStatus.Succeeded:
                        result.StatusCode = (HttpStatusCode)Convert.ToInt32(
                            operation.Element(wa + "HttpStatusCode").Value);
                        done = true;
                        break;
                }
 
                if (!done && DateTime.UtcNow > endPollTime)
                {
                    result.Status = OperationStatus.TimedOut;
                    done = true;
                }
            }
 
            return result;
        }
 
        /// <summary>
        /// Gets the certificate matching the thumbprint from the local store.
        /// Throws an ArgumentException if a matching certificate is not found.
        /// </summary>
        /// <param name="thumbprint">The thumbprint of the certificate to find.</param>
        /// <returns>The certificate with the specified thumbprint.</returns>
        private static X509Certificate2 GetCertificate(string thumbprint)
        {
            List<StoreLocation> locations = new List<StoreLocation> 
            { 
                StoreLocation.CurrentUser, 
                StoreLocation.LocalMachine 
            };
 
            foreach (var location in locations)
            {
                X509Store store = new X509Store("My", location);
                try
                {
                    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
                    X509Certificate2Collection certificates = store.Certificates.Find(
                        X509FindType.FindByThumbprint, thumbprint, false);
                    if (certificates.Count == 1)
                    {
                        return certificates[0];
                    }
                }
                finally
                {
                    store.Close();
                }
            }
 
            throw new ArgumentException(string.Format(
                "A Certificate with Thumbprint '{0}' could not be located.",
                thumbprint));
        }
 
        /// <summary>
        /// A helper function to invoke a Service Management REST API operation.
        /// Throws an ApplicationException on unexpected status code results.
        /// </summary>
        /// <param name="uri">The URI of the operation to invoke using a web request.</param>
        /// <param name="method">The method of the web request, GET, PUT, POST, or DELETE.</param>
        /// <param name="expectedCode">The expected status code.</param>
        /// <param name="requestBody">The XML body to send with the web request. Use null to send no request body.</param>
        /// <param name="responseBody">The XML body returned by the request, if any.</param>
        /// <returns>The requestId returned by the operation.</returns>
        private static string InvokeRequest(
            Uri uri,
            string method,
            HttpStatusCode expectedCode,
            XDocument requestBody,
            out XDocument responseBody)
        {
            responseBody = null;
            string requestId = String.Empty;
 
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
            request.Method = method;
            request.Headers.Add("x-ms-Version", Version);
            request.ClientCertificates.Add(Certificate);
            request.ContentType = "application/xml";
 
            if (requestBody != null)
            {
                using (Stream requestStream = request.GetRequestStream())
                {
                    using (StreamWriter streamWriter = new StreamWriter(
                        requestStream, System.Text.UTF8Encoding.UTF8))
                    {
                        requestBody.Save(streamWriter, SaveOptions.DisableFormatting);
                    }
                }
            }
 
            HttpWebResponse response;
            HttpStatusCode statusCode = HttpStatusCode.Unused;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                // GetResponse throws a WebException for 4XX and 5XX status codes
                response = (HttpWebResponse)ex.Response;
            }
 
            try
            {
                statusCode = response.StatusCode;
                if (response.ContentLength > 0)
                {
                    using (XmlReader reader = XmlReader.Create(response.GetResponseStream()))
                    {
                        responseBody = XDocument.Load(reader);
                    }
                }
 
                if (response.Headers != null)
                {
                    requestId = response.Headers["x-ms-request-id"];
                }
            }
            finally
            {
                response.Close();
            }
 
            if (!statusCode.Equals(expectedCode))
            {
                throw new ApplicationException(string.Format(
                    "Call to {0} returned an error:{1}Status Code: {2} ({3}):{1}{4}",
                    uri.ToString(),
                    Environment.NewLine,
                    (int)statusCode,
                    statusCode,
                    responseBody.ToString(SaveOptions.OmitDuplicateNamespaces)));
            }
 
            return requestId;
        }
    }
 
    /// <summary>
    /// Helpful extension methods for converting strings to and from Base-64.
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// Converts a UTF-8 string to a Base-64 version of the string.
        /// </summary>
        /// <param name="s">The string to convert to Base-64.</param>
        /// <returns>The Base-64 converted string.</returns>
        public static string ToBase64(this string s)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(s);
            return Convert.ToBase64String(bytes);
        }
 
        /// <summary>
        /// Converts a Base-64 encoded string to UTF-8.
        /// </summary>
        /// <param name="s">The string to convert from Base-64.</param>
        /// <returns>The converted UTF-8 string.</returns>
        public static string FromBase64(this string s)
        {
            byte[] bytes = Convert.FromBase64String(s);
            return System.Text.Encoding.UTF8.GetString(bytes);
        }
    }
}

Cet exemple de programme génère une sortie de console similaire à ce qui suit :

Called Create Storage Account operation: requestId 8ba8bd9cdc50472892a0b3cd3659b297
In progress for 0 seconds
In progress for 20 seconds
In progress for 41 seconds
In progress for 61 seconds
In progress for 82 seconds
In progress for 103 seconds
Succeeded: Operation 8ba8bd9cdc50472892a0b3cd3659b297 completed after 123 seconds with status 200 (OK)
New Storage Account Properties for myexamplestorage1:
<StorageService xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Url>https://management.core.windows.net/01234567-89ab-cdef-0123-456789abcdef/services/storageservices/myexamplestorage1</Url>
  <ServiceName>myexamplestorage1</ServiceName>
  <StorageServiceProperties>
    <Description>Description for my example storage account</Description>
    <Location>North Central US</Location>
    <Label>My example storage account label</Label>
    <Status>Created</Status>
    <Endpoints>
      <Endpoint>http://myexamplestorage1.blob.core.windows.net/</Endpoint>
      <Endpoint>http://myexamplestorage1.queue.core.windows.net/</Endpoint>
      <Endpoint>http://myexamplestorage1.table.core.windows.net/</Endpoint>
    </Endpoints>
  </StorageServiceProperties>
</StorageService>
Press any key to continue:

Afficher:
© 2014 Microsoft