Créer et utiliser un service d’application

Important

Les listes de code de cette rubrique sont C# uniquement. Pour obtenir un exemple d’application App Service en C++/WinRT et en C#, consultez Exemple d’application App Service.

Les services d’application sont des applications UWP qui fournissent des services à d’autres applications UWP. Ils sont analogues aux services web, sur un appareil. Un service d’application s’exécute sous forme de tâche en arrière-plan dans l’application hôte et peut fournir son service à d’autres applications. Par exemple, un service d’application peut fournir un service de scanneur de code-barres que d’autres applications peuvent utiliser. Ou peut-être qu’une suite d’applications Entreprise a un service d’application de vérification orthographique commun qui est disponible pour les autres applications de la suite. Les services d’application vous permettent de créer des services sans interface utilisateur que les applications peuvent appeler sur le même appareil et à compter de Windows 10 version 1607 sur les appareils distants.

À partir de Windows 10 version 1607, vous pouvez créer des services d’application qui s’exécutent dans le même processus que l’application hôte. Cet article se concentre sur la création et la consommation d’un service d’application qui s’exécute dans un processus en arrière-plan distinct. Pour plus d’informations sur l’exécution d’un service d’application dans le même processus que son application hôte, consultez Convertir un service d’application pour l’exécuter dans le même processus que le fournisseur.

Créer un projet de fournisseur de service d’application

Dans la procédure décrite ici, nous allons créer tous les éléments dans une seule solution par souci de simplicité.

  1. Dans Visual Studio 2015 ou version ultérieure, créez un projet d’application UWP et nommez-le AppServiceProvider.

    1. Sélectionnez Fichier > nouveau > projet...
    2. Dans la boîte de dialogue Créer un projet , sélectionnez Application vide (Windows universel) C#. Il s’agit de l’application qui rend le service d’application disponible pour d’autres applications UWP.
    3. Cliquez sur Suivant, puis nommez le projet AppServiceProvider, choisissez un emplacement pour celui-ci, puis cliquez sur Créer.
  2. Lorsque vous êtes invité à sélectionner une versioncible et minimale pour le projet, sélectionnez au moins 10.0.14393. Si vous souhaitez utiliser le nouvel attribut SupportsMultipleInstances, vous devez utiliser Visual Studio 2017 ou Visual Studio 2019 et cibler la version 10.0.15063 (Windows 10 Creators Update) ou ultérieure.

Ajouter une extension app service à Package.appxmanifest

Dans le projet AppServiceProvider , ouvrez le fichier Package.appxmanifest dans un éditeur de texte :

  1. Cliquez dessus avec le bouton droit dans le Explorateur de solutions.
  2. Sélectionnez Ouvrir avec.
  3. Sélectionnez Éditeur XML (texte).

Ajoutez l’extension suivante AppService à l’intérieur de l’élément <Application> . Cet exemple publie le service com.microsoft.inventory, qui identifie cette application en tant que fournisseur de service d’application. Le service proprement dit est implémenté sous forme de tâche en arrière-plan. Le projet App Service expose le service à d’autres applications. Nous vous recommandons d’utiliser un style de nom de domaine inverse pour le nom du service.

Notez que le xmlns:uap4 préfixe d’espace de noms et l’attribut uap4:SupportsMultipleInstances sont valides uniquement si vous ciblez le Kit de développement logiciel (SDK) Windows version 10.0.15063 ou ultérieure. Vous pouvez les supprimer en toute sécurité si vous ciblez d’anciennes versions du Kit de développement logiciel (SDK).

Notes

Pour obtenir un exemple d’application App Service en C++/WinRT et en C#, consultez Exemple d’application App Service.

<Package
    ...
    xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
    xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
    ...
    <Applications>
        <Application Id="AppServiceProvider.App"
          Executable="$targetnametoken$.exe"
          EntryPoint="AppServiceProvider.App">
          ...
          <Extensions>
            <uap:Extension Category="windows.appService" EntryPoint="MyAppService.Inventory">
              <uap3:AppService Name="com.microsoft.inventory" uap4:SupportsMultipleInstances="true"/>
            </uap:Extension>
          </Extensions>
          ...
        </Application>
    </Applications>

L’attribut Category identifie cette application en tant que fournisseur de services d’application.

L’attribut EntryPoint identifie la classe qualifiée d’espace de noms qui implémente le service, que nous allons implémenter ensuite.

L’attribut SupportsMultipleInstances indique que chaque fois que le service d’application est appelé, il doit s’exécuter dans un nouveau processus. Cette fonctionnalité n’est pas obligatoire, mais elle est disponible si vous avez besoin de cette fonctionnalité et que vous ciblez le Kit de développement logiciel (SDK) 10.0.15063 (Windows 10 Creators Update) ou version ultérieure. Il doit également être préfacé par l’espace de uap4 noms.

Créer le service d’application

  1. Un service d’application peut être implémenté en tant que tâche en arrière-plan. Cela permet à une application de premier plan d’appeler un service d’application dans une autre application. Pour créer un service d’application en tant que tâche en arrière-plan, ajoutez un nouveau projet de composant Windows Runtime à la solution (Fichier > Ajouter un > nouveau projet) nommé MyAppService. Dans la boîte de dialogue Ajouter un nouveau projet, choisissez Installé > Visual C# > Windows Runtime Component (Windows universel).

  2. Dans le projet AppServiceProvider, ajoutez une référence de projet à projet au nouveau projet MyAppService (dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet >AppServiceProviderAjouter une>solution deprojets> deréférence>, sélectionnez MyAppService>OK). Cette étape est critique, car si vous n’ajoutez pas la référence, le service d’application ne se connecte pas au moment de l’exécution.

  3. Dans le projet MyAppService , ajoutez les instructions using suivantes en haut de Class1.cs :

    using Windows.ApplicationModel.AppService;
    using Windows.ApplicationModel.Background;
    using Windows.Foundation.Collections;
    
  4. Renommez Class1.cs en Inventory.cs et remplacez le code stub pour Class1 par une nouvelle classe de tâches en arrière-plan nommée Inventory :

    public sealed class Inventory : IBackgroundTask
    {
        private BackgroundTaskDeferral backgroundTaskDeferral;
        private AppServiceConnection appServiceconnection;
        private String[] inventoryItems = new string[] { "Robot vacuum", "Chair" };
        private double[] inventoryPrices = new double[] { 129.99, 88.99 };
    
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            // Get a deferral so that the service isn't terminated.
            this.backgroundTaskDeferral = taskInstance.GetDeferral();
    
            // Associate a cancellation handler with the background task.
            taskInstance.Canceled += OnTaskCanceled;
    
            // Retrieve the app service connection and set up a listener for incoming app service requests.
            var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
            appServiceconnection = details.AppServiceConnection;
            appServiceconnection.RequestReceived += OnRequestReceived;
        }
    
        private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            // This function is called when the app service receives a request.
        }
    
        private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            if (this.backgroundTaskDeferral != null)
            {
                // Complete the service deferral.
                this.backgroundTaskDeferral.Complete();
            }
        }
    }
    

    C’est dans cette classe que le service d’application effectuera son travail.

    L’exécution est appelée lors de la création de la tâche en arrière-plan. Étant donné que les tâches en arrière-plan sont terminées une fois l’exécution terminée, le code supprime un report afin que la tâche en arrière-plan reste en mesure de traiter les demandes. Un service d’application implémenté en tant que tâche en arrière-plan reste actif pendant environ 30 secondes après avoir reçu un appel, sauf s’il est appelé à nouveau dans cette fenêtre de temps ou si un report est supprimé. Si le service d’application est implémenté dans le même processus que l’appelant, la durée de vie du service d’application est liée à la durée de vie de l’appelant.

    La durée de vie du service d’application dépend de l’appelant :

    • Si l’appelant est au premier plan, la durée de vie du service d’application est la même que celle de l’appelant.
    • Si l’appelant est en arrière-plan, le service d’application dispose de 30 secondes pour s’exécuter. La prise d’un report fournit une fois supplémentaire de 5 secondes.

    OnTaskCanceled est appelé lorsque la tâche est annulée. La tâche est annulée lorsque l’application cliente supprime AppServiceConnection, que l’application cliente est suspendue, que le système d’exploitation est arrêté ou en veille, ou que le système d’exploitation manque de ressources pour exécuter la tâche.

Écrire le code du service d’application

OnRequestReceived est l’emplacement où passe le code de l’app service. Remplacez le stub OnRequestReceived dans Inventory.cs de MyAppService par le code de cet exemple. Ce code obtient un index pour un article en stock et le transmet au service avec une chaîne de commande pour récupérer le nom et le prix de l’article en stock spécifié. Pour vos propres projets, ajoutez du code de gestion des erreurs.

private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
    // Get a deferral because we use an awaitable API below to respond to the message
    // and we don't want this call to get canceled while we are waiting.
    var messageDeferral = args.GetDeferral();

    ValueSet message = args.Request.Message;
    ValueSet returnData = new ValueSet();

    string command = message["Command"] as string;
    int? inventoryIndex = message["ID"] as int?;

    if (inventoryIndex.HasValue &&
        inventoryIndex.Value >= 0 &&
        inventoryIndex.Value < inventoryItems.GetLength(0))
    {
        switch (command)
        {
            case "Price":
            {
                returnData.Add("Result", inventoryPrices[inventoryIndex.Value]);
                returnData.Add("Status", "OK");
                break;
            }

            case "Item":
            {
                returnData.Add("Result", inventoryItems[inventoryIndex.Value]);
                returnData.Add("Status", "OK");
                break;
            }

            default:
            {
                returnData.Add("Status", "Fail: unknown command");
                break;
            }
        }
    }
    else
    {
        returnData.Add("Status", "Fail: Index out of range");
    }

    try
    {
        // Return the data to the caller.
        await args.Request.SendResponseAsync(returnData);
    }
    catch (Exception e)
    {
        // Your exception handling code here.
    }
    finally
    {
        // Complete the deferral so that the platform knows that we're done responding to the app service call.
        // Note for error handling: this must be called even if SendResponseAsync() throws an exception.
        messageDeferral.Complete();
    }
}

Notez que OnRequestReceived est asynchrone , car nous effectuons un appel de méthode attendable à SendResponseAsync dans cet exemple.

Un report est effectué afin que le service puisse utiliser des méthodes asynchrones dans le gestionnaire OnRequestReceived . Il garantit que l’appel à OnRequestReceived ne se termine pas tant que le traitement du message n’est pas terminé. SendResponseAsync envoie le résultat à l’appelant. SendResponseAsync n’indique pas l’achèvement de l’appel. C’est l’achèvement du report qui signale à SendMessageAsyncqu’OnRequestReceived a terminé . L’appel à SendResponseAsync est encapsulé dans un bloc try/finally, car vous devez effectuer le report même si SendResponseAsync lève une exception.

Les services d’application utilisent des objets ValueSet pour échanger des informations. La taille des données que vous pouvez transmettre est limitée uniquement par les ressources système. Il n’y a aucune clé prédéfinie utilisable dans votre classe ValueSet. Vous devez déterminer quelles valeurs de clé vous allez utiliser pour définir le protocole de votre service d’application. L’appelant doit être écrit avec ce protocole à l’esprit. Dans cet exemple, nous avons choisi une clé nommée Command qui a une valeur qui indique si nous voulons que le service d’application fournisse le nom de l’élément d’inventaire ou son prix. L’index du nom de l’inventaire est stocké sous la ID clé. La valeur de retour est stockée sous la Result clé.

Une énumération AppServiceClosedStatus est renvoyée à l’appelant pour indiquer si l’appel au service d’application a réussi ou échoué. Un exemple de la façon dont l’appel au service d’application peut échouer est si le système d’exploitation abandonne le point de terminaison de service parce que ses ressources ont été dépassées. Vous pouvez renvoyer des informations d’erreur supplémentaires via la classe ValueSet. Dans cet exemple, nous utilisons une clé nommée Status pour retourner des informations d’erreur plus détaillées à l’appelant.

L’appel à SendResponseAsync renvoie la classe ValueSet à l’appelant.

Déployer l’application de service et obtenir le nom de la famille de packages

Le fournisseur de service d’application doit être déployé avant de pouvoir l’appeler à partir d’un client. Vous pouvez le déployer en sélectionnant Générer > déployer la solution dans Visual Studio.

Vous aurez également besoin du nom de famille de package du fournisseur de services d’application pour l’appeler. Vous pouvez l’obtenir en ouvrant le fichier Package.appxmanifest du projet AppServiceProvider en mode concepteur (double-cliquez dessus dans le Explorateur de solutions). Sélectionnez l’onglet Empaquetage , copiez la valeur en regard de Nom de la famille du package, puis collez-la quelque part comme bloc-notes pour l’instant.

Écrire un client pour appeler le service d’application

  1. Ajoutez un nouveau projet d’application universelle Windows vide à la solution avec Fichier > Ajouter un > nouveau projet. Dans la boîte de dialogue Ajouter un nouveau projet , choisissez Installé > Visual C# > Blank App (Windows universel) et nommez-la ClientApp.

  2. Dans le projet ClientApp , ajoutez l’instruction using suivante en haut de MainPage.xaml.cs :

    using Windows.ApplicationModel.AppService;
    
  3. Ajoutez une zone de texte appelée textBox et un bouton à MainPage.xaml.

  4. Ajoutez un gestionnaire de boutons pour le bouton appelé button_Click, puis ajoutez le mot clé asynchrone à la signature du gestionnaire de boutons.

  5. Remplacez le stub de votre gestionnaire d’événement de clic pour le bouton par le code suivant. Veillez à inclure la déclaration de champ inventoryService.

    private AppServiceConnection inventoryService;
    
    private async void button_Click(object sender, RoutedEventArgs e)
    {
       // Add the connection.
       if (this.inventoryService == null)
       {
           this.inventoryService = new AppServiceConnection();
    
           // Here, we use the app service name defined in the app service 
           // provider's Package.appxmanifest file in the <Extension> section.
           this.inventoryService.AppServiceName = "com.microsoft.inventory";
    
           // Use Windows.ApplicationModel.Package.Current.Id.FamilyName 
           // within the app service provider to get this value.
           this.inventoryService.PackageFamilyName = "Replace with the package family name";
    
           var status = await this.inventoryService.OpenAsync();
    
           if (status != AppServiceConnectionStatus.Success)
           {
               textBox.Text= "Failed to connect";
               this.inventoryService = null;
               return;
           }
       }
    
       // Call the service.
       int idx = int.Parse(textBox.Text);
       var message = new ValueSet();
       message.Add("Command", "Item");
       message.Add("ID", idx);
       AppServiceResponse response = await this.inventoryService.SendMessageAsync(message);
       string result = "";
    
       if (response.Status == AppServiceResponseStatus.Success)
       {
           // Get the data  that the service sent to us.
           if (response.Message["Status"] as string == "OK")
           {
               result = response.Message["Result"] as string;
           }
       }
    
       message.Clear();
       message.Add("Command", "Price");
       message.Add("ID", idx);
       response = await this.inventoryService.SendMessageAsync(message);
    
       if (response.Status == AppServiceResponseStatus.Success)
       {
           // Get the data that the service sent to us.
           if (response.Message["Status"] as string == "OK")
           {
               result += " : Price = " + response.Message["Result"] as string;
           }
       }
    
       textBox.Text = result;
    }
    

    Remplacez le nom de la famille de packages dans la ligne this.inventoryService.PackageFamilyName = "Replace with the package family name"; par le nom de la famille de packages du projet AppServiceProvider que vous avez obtenu ci-dessus dans Déployer l’application de service et obtenir le nom de la famille de packages.

    Notes

    Veillez à coller le littéral de chaîne au lieu de le placer dans une variable. Cela ne fonctionnera pas si vous utilisez une variable.

    Le code établit tout d’abord une connexion avec le service d’application. La connexion reste ouverte jusqu’à ce que vous supprimiez this.inventoryService. Le nom du service d’application doit correspondre à l’attribut de Name l’élément AppService que vous avez ajouté au fichier Package.appxmanifest du projet AppServiceProvider. Dans cet exemple, il s’agit de <uap3:AppService Name="com.microsoft.inventory"/>.

    Un ValueSet nommé message est créé pour spécifier la commande que nous voulons envoyer au service d’application. L’exemple de service d’application attend une commande pour indiquer laquelle des deux actions effectuer. Nous obtenons l’index à partir de la zone de texte de l’application cliente, puis nous appelons le service avec la Item commande pour obtenir la description de l’élément. Ensuite, nous effectuons l’appel avec la Price commande pour obtenir le prix de l’article. Le texte du bouton est défini en fonction du résultat.

    Étant donné que AppServiceResponseStatus indique uniquement si le système d’exploitation a pu connecter l’appel au service d’application, nous case activée la clé dans le StatusValueSet que nous recevons du service d’application pour nous assurer qu’il a été en mesure de répondre à la demande.

  6. Définissez le projet ClientApp comme projet de démarrage (cliquez dessus avec le bouton droit dans le Explorateur de solutions>Set as StartUp Project) et exécutez la solution. Entrez le chiffre 1 dans la zone de texte et cliquez sur le bouton. Le service doit renvoyer « Chair : Price = 88.99 ».

    exemple d’application affichant chair price=88.99

Si l’appel du service d’application échoue, case activée les éléments suivants dans le projet ClientApp :

  1. Vérifiez que le nom de la famille de packages attribué à la connexion de service d’inventaire correspond au nom de la famille de packages de l’application AppServiceProvider . Consultez la ligne dans button_Click avec this.inventoryService.PackageFamilyName = "...";.
  2. Dans button_Click, vérifiez que le nom du service d’application affecté à la connexion du service d’inventaire correspond au nom du service d’application dans le fichier Package.appxmanifestd’AppServiceProvider. Voir this.inventoryService.AppServiceName = "com.microsoft.inventory";.
  3. Vérifiez que l’application AppServiceProvider a été déployée. (Dans le Explorateur de solutions, cliquez avec le bouton droit sur la solution, puis choisissez Déployer la solution).

Déboguer le service d’application

  1. Assurez-vous que la solution est déployée avant le débogage, car l’application du fournisseur app service doit être déployée avant que le service puisse être appelé. (Dans Visual Studio, Générer > Déployer la solution).
  2. Dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet AppServiceProvider et choisissez Propriétés. Dans l’onglet Déboguer, définissez Action de démarrage sur Ne pas lancer, mais déboguer mon code au démarrage. (Notez que si vous utilisez C++ pour implémenter votre fournisseur app service, à partir de l’onglet Débogage , vous définissez Lancer l’application sur Non.
  3. Dans le projet MyAppService , dans le fichier Inventory.cs , définissez un point d’arrêt dans OnRequestReceived.
  4. Définissez le projet AppServiceProvider comme projet de démarrage, puis appuyez sur F5.
  5. Démarrez ClientApp à partir du menu Démarrer (pas à partir de Visual Studio).
  6. Entrez le chiffre 1 dans la zone de texte et appuyez sur le bouton. Le débogueur s’arrête dans l’appel au service d’application sur le point d’arrêt défini dans votre service d’application.

Déboguer le client

  1. Suivez les instructions de l’étape précédente pour déboguer le client qui appelle le service d’application.
  2. Lancez ClientApp à partir du menu Démarrer.
  3. Attachez le débogueur au processus ClientApp.exe (et non au processusApplicationFrameHost.exe ). (Dans Visual Studio, choisissez Déboguer > Attacher au processus….)
  4. Dans le projet ClientApp , définissez un point d’arrêt dans button_Click.
  5. Les points d’arrêt du client et du service d’application sont désormais atteints lorsque vous entrez le numéro 1 dans la zone de texte de ClientApp et cliquez sur le bouton.

Résolution des problèmes généraux d’App Service

Si vous rencontrez un status AppUnavailable après avoir essayé de vous connecter à un service d’application, case activée les éléments suivants :

  • Vérifiez que le projet de fournisseur app service et le projet App Service sont déployés. Les deux doivent être déployés avant d’exécuter le client, car sinon, le client n’aura rien à se connecter. Vous pouvez déployer à partir de Visual Studio à l’aide de Build>Deploy Solution.
  • Dans le Explorateur de solutions, assurez-vous que votre projet de fournisseur d’application dispose d’une référence de projet à projet au projet qui implémente le service d’application.
  • Vérifiez que l’entrée <Extensions> et ses éléments enfants ont été ajoutés au fichier Package.appxmanifest appartenant au projet du fournisseur app service, comme indiqué ci-dessus dans Ajouter une extension app service à Package.appxmanifest.
  • Vérifiez que la chaîne AppServiceConnection.AppServiceName dans votre client qui appelle le fournisseur app service correspond au <uap3:AppService Name="..." /> spécifié dans le fichier Package.appxmanifest du projet du fournisseur d’application.
  • Vérifiez que AppServiceConnection.PackageFamilyName correspond au nom de la famille de packages du composant fournisseur app service, comme indiqué ci-dessus dans Ajouter une extension app service à Package.appxmanifest
  • Pour les services d’application hors processus tels que celui de cet exemple, vérifiez que le EntryPoint spécifié dans l’élément <uap:Extension ...> du fichier Package.appxmanifest de votre projet de fournisseur d’application correspond à l’espace de noms et au nom de classe de la classe publique qui implémente IBackgroundTask dans votre projet App Service.

Résoudre les problèmes de débogage

Si le débogueur ne s’arrête pas aux points d’arrêt de votre fournisseur app service ou de vos projets App Service, case activée les éléments suivants :

  • Vérifiez que le projet de fournisseur app service et le projet App Service sont déployés. Les deux doivent être déployés avant d’exécuter le client. Vous pouvez les déployer à partir de Visual Studio à l’aide de Build>Deploy Solution.
  • Vérifiez que le projet que vous souhaitez déboguer est défini comme projet de démarrage et que les propriétés de débogage de ce projet sont définies pour ne pas exécuter le projet lorsque la touche F5 est enfoncée. Cliquez avec le bouton droit sur le projet, cliquez sur Propriétés, puis sur Déboguer (ou Débogage en C++). En C#, remplacez l’action Démarrer par Ne pas lancer, mais déboguez mon code au démarrage. En C++, définissez Lancer l’application sur Non.

Remarques

Cet exemple fournit une introduction à la création d’un service d’application qui s’exécute en tant que tâche en arrière-plan et à son appel à partir d’une autre application. Les points clés à noter sont les suivants :

  • Créez une tâche en arrière-plan pour héberger le service d’application.
  • Ajoutez l’extension windows.appService au fichier Package.appxmanifest du fournisseur de services d’application.
  • Obtenez le nom de la famille de packages du fournisseur app service afin que nous puissions nous y connecter à partir de l’application cliente.
  • Ajoutez une référence de projet à projet à partir du projet de fournisseur App Service au projet App Service.
  • Utilisez Windows.ApplicationModel.AppService.AppServiceConnection pour appeler le service.

Code complet pour MyAppService

using System;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.Foundation.Collections;

namespace MyAppService
{
    public sealed class Inventory : IBackgroundTask
    {
        private BackgroundTaskDeferral backgroundTaskDeferral;
        private AppServiceConnection appServiceconnection;
        private String[] inventoryItems = new string[] { "Robot vacuum", "Chair" };
        private double[] inventoryPrices = new double[] { 129.99, 88.99 };

        public void Run(IBackgroundTaskInstance taskInstance)
        {
            // Get a deferral so that the service isn't terminated.
            this.backgroundTaskDeferral = taskInstance.GetDeferral();

            // Associate a cancellation handler with the background task.
            taskInstance.Canceled += OnTaskCanceled;

            // Retrieve the app service connection and set up a listener for incoming app service requests.
            var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
            appServiceconnection = details.AppServiceConnection;
            appServiceconnection.RequestReceived += OnRequestReceived;
        }

        private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            // Get a deferral because we use an awaitable API below to respond to the message
            // and we don't want this call to get canceled while we are waiting.
            var messageDeferral = args.GetDeferral();

            ValueSet message = args.Request.Message;
            ValueSet returnData = new ValueSet();

            string command = message["Command"] as string;
            int? inventoryIndex = message["ID"] as int?;

            if (inventoryIndex.HasValue &&
                 inventoryIndex.Value >= 0 &&
                 inventoryIndex.Value < inventoryItems.GetLength(0))
            {
                switch (command)
                {
                    case "Price":
                        {
                            returnData.Add("Result", inventoryPrices[inventoryIndex.Value]);
                            returnData.Add("Status", "OK");
                            break;
                        }

                    case "Item":
                        {
                            returnData.Add("Result", inventoryItems[inventoryIndex.Value]);
                            returnData.Add("Status", "OK");
                            break;
                        }

                    default:
                        {
                            returnData.Add("Status", "Fail: unknown command");
                            break;
                        }
                }
            }
            else
            {
                returnData.Add("Status", "Fail: Index out of range");
            }

            // Return the data to the caller.
            await args.Request.SendResponseAsync(returnData);

            // Complete the deferral so that the platform knows that we're done responding to the app service call.
            // Note for error handling: this must be called even if SendResponseAsync() throws an exception.
            messageDeferral.Complete();
        }


        private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            if (this.backgroundTaskDeferral != null)
            {
                // Complete the service deferral.
                this.backgroundTaskDeferral.Complete();
            }
        }
    }
}