Compartilhar via


Criar e consumir um serviço de app

Importante

As listagens de código neste tópico são somente C#. Para obter um aplicativo de exemplo do serviço de aplicativo em C++/WinRT , bem como em C#, consulte Aplicativo de exemplo do serviço de aplicativo.

Os serviços de aplicativos são aplicativos UWP que fornecem serviços para outros aplicativos UWP. Eles são análogos aos serviços da web, em um dispositivo. Um serviço de aplicativo é executado como uma tarefa em segundo plano no aplicativo host e pode fornecer seu serviço a outros aplicativos. Por exemplo, um serviço de aplicativo pode fornecer um serviço de scanner de código de barras que outros aplicativos podem usar. Ou talvez uma suíte de aplicativos Enterprise tenha um serviço de aplicativo de verificação ortográfica comum que está disponível para os outros aplicativos da suíte. Os serviços de aplicativo permitem criar serviços sem interface do usuário que os aplicativos podem chamar no mesmo dispositivo e, a partir do Windows 10, versão 1607, em dispositivos remotos.

A partir do Windows 10, versão 1607, você pode criar serviços de aplicativo que são executados no mesmo processo que o aplicativo host. Este artigo se concentra na criação e no consumo de um serviço de aplicativo que é executado em um processo separado em segundo plano. Consulte Converter um serviço de aplicativo para ser executado no mesmo processo que seu aplicativo host para obter mais detalhes sobre como executar um serviço de aplicativo no mesmo processo que o provedor.

Criar um novo projeto de provedor de serviços de aplicativo

Neste tutorial, criaremos tudo em uma solução para simplificar.

  1. No Visual Studio 2015 ou posterior, crie um novo projeto de aplicativo UWP e nomeie-o AppServiceProvider.

    1. Selecione Arquivo > Novo > Projeto...
    2. Na caixa de diálogo Criar um novo projeto, selecione Aplicativo em Branco (Universal do Windows) C#. Esse será o aplicativo que disponibilizará o serviço de aplicativo para outros aplicativos UWP.
    3. Clique em Avançar e nomeie o projeto AppServiceProvider, escolha um local para ele e clique em Criar.
  2. Quando solicitado a selecionar uma versão de destino e mínima para o projeto, selecione pelo menos 10.0.14393. Se você quiser usar o novo atributo SupportsMultipleInstances , deverá estar usando o Visual Studio 2017 ou o Visual Studio 2019 e ter como destino 10.0.15063 (Windows 10 Creators Update) ou posterior.

Adicionar uma extensão do serviço de aplicativo a Package.appxmanifest

No projeto AppServiceProvider, abra o arquivo Package.appxmanifest em um editor de texto:

  1. Clique com o botão direito do mouse no Gerenciador de Soluções.
  2. Selecione Abrir com.
  3. Selecione o Editor XML (Texto).

Adicione a seguinte AppService extensão dentro do <Application> elemento. Este exemplo anuncia o com.microsoft.inventory serviço e é o que identifica esse aplicativo como um provedor de serviços de aplicativo. O serviço real será implementado como uma tarefa em segundo plano. O projeto do serviço de aplicativo expõe o serviço a outros aplicativos. Recomendamos usar um estilo de nome de domínio reverso para o nome do serviço.

Observe que o prefixo de xmlns:uap4 namespace e o uap4:SupportsMultipleInstances atributo só serão válidos se você estiver direcionando SDK do Windows versão 10.0.15063 ou posterior. Você pode removê-los com segurança se estiver direcionando versões mais antigas do SDK.

Observação

Para obter um aplicativo de exemplo do serviço de aplicativo em C++/WinRT , bem como em C#, consulte Aplicativo de exemplo do serviço de aplicativo.

<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>

O Category atributo identifica esse aplicativo como um provedor de serviços de aplicativo.

O EntryPoint atributo identifica a classe qualificada de namespace que implementa o serviço, que implementaremos a seguir.

O SupportsMultipleInstances atributo indica que cada vez que o serviço de aplicativo é chamado, ele deve ser executado em um novo processo. Isso não é necessário, mas está disponível para você se precisar dessa funcionalidade e estiver direcionando o SDK 10.0.15063 (Windows 10 Creators Update) ou posterior. Ele também deve ser precedido uap4 pelo namespace.

Criar o serviço de aplicativo

  1. Um serviço de aplicativo pode ser implementado como uma tarefa em segundo plano. Isso permite que um aplicativo em primeiro plano invoque um serviço de aplicativo em outro aplicativo. Para criar um serviço de aplicativo como uma tarefa em segundo plano, adicione um novo projeto de componente do Tempo de Execução do Windows à solução (Arquivo > Adicionar > Novo Projeto) chamado MyAppService. Na caixa de diálogo Adicionar Novo Projeto, escolha Componente do Tempo de Execução do Windows do Visual C# > Instalado > (Universal do Windows).

  2. No projeto AppServiceProvider, adicione uma referência projeto a projeto ao novo projeto MyAppService (no Gerenciador de Soluções, clique com o botão direito do mouse no projeto >AppServiceProvider Adicionar>Solução de Projetos de Referência>>, selecione MyAppService>OK). Essa etapa é crítica porque, se você não adicionar a referência, o serviço de aplicativo não se conectará em runtime.

  3. No projeto MyAppService, adicione as seguintes instruções using à parte superior de Class1.cs:

    using Windows.ApplicationModel.AppService;
    using Windows.ApplicationModel.Background;
    using Windows.Foundation.Collections;
    
  4. Renomeie Class1.cs para Inventory.cs e substitua o código de stub de Class1 por uma nova classe de tarefa em segundo plano chamada 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();
            }
        }
    }
    

    Essa classe é onde o serviço de aplicativo fará seu trabalho.

    Run é chamado quando a tarefa em segundo plano é criada. Como as tarefas em segundo plano são encerradas após a conclusão da execução , o código faz um adiamento para que a tarefa em segundo plano permaneça ativa para atender às solicitações. Um serviço de aplicativo implementado como uma tarefa em segundo plano permanecerá ativo por cerca de 30 segundos depois de receber uma chamada, a menos que seja chamado novamente dentro dessa janela de tempo ou um adiamento seja retirado. Se o serviço de aplicativo for implementado no mesmo processo que o chamador, o tempo de vida do serviço de aplicativo será vinculado ao tempo de vida do chamador.

    O tempo de vida do serviço de aplicativo depende do chamador:

    • Se o chamador estiver em primeiro plano, o tempo de vida do serviço de aplicativo será o mesmo que o chamador.
    • Se o chamador estiver em segundo plano, o serviço de aplicativo terá 30 segundos para ser executado. Fazer um adiamento fornece um adicional de 5 segundos de uma vez.

    OnTaskCanceled é chamado quando a tarefa é cancelada. A tarefa é cancelada quando o aplicativo cliente descarta o AppServiceConnection, o aplicativo cliente é suspenso, o sistema operacional é desligado ou dorme ou o sistema operacional fica sem recursos para executar a tarefa.

Escrever o código para o serviço de aplicativo

OnRequestReceived é para onde vai o código do serviço de aplicativo. Substitua o stub OnRequestReceived no Inventory.cs do MyAppService pelo código deste exemplo. Esse código obtém um índice para um item de inventário e o passa, juntamente com uma cadeia de caracteres de comando, para o serviço para recuperar o nome e o preço do item de inventário especificado. Para seus próprios projetos, adicione o código de tratamento de erros.

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();
    }
}

Observe que OnRequestReceived é assíncrono porque fazemos uma chamada de método aguardável para SendResponseAsync neste exemplo.

Um adiamento é feito para que o serviço possa usar métodos assíncronos no manipulador OnRequestReceived . Ele garante que a chamada para OnRequestReceived não seja concluída até que termine de processar a mensagem. SendResponseAsync envia o resultado para o chamador. SendResponseAsync não sinaliza a conclusão da chamada. É a conclusão do adiamento que sinaliza para SendMessageAsync que OnRequestReceived foi concluído. A chamada para SendResponseAsync é encapsulada em um bloco try/finally porque você deve concluir o adiamento mesmo que SendResponseAsync gere uma exceção.

Os serviços de aplicativo usam objetos ValueSet para trocar informações. O tamanho dos dados que você pode passar é limitado apenas pelos recursos do sistema. Não há chaves predefinidas para você usar em seu ValueSet. Você deve determinar quais valores de chave usará para definir o protocolo para o serviço de aplicativo. O chamador deve ser escrito com esse protocolo em mente. Neste exemplo, escolhemos uma chave chamada Command que tem um valor que indica se queremos que o serviço de aplicativo forneça o nome do item de inventário ou seu preço. O índice do nome do inventário é armazenado sob a ID chave. O valor retornado é armazenado sob a Result chave.

Uma enumeração AppServiceClosedStatus é retornada ao chamador para indicar se a chamada para o serviço de aplicativo foi bem-sucedida ou falhou. Um exemplo de como a chamada para o serviço de aplicativo pode falhar é se o sistema operacional anular o ponto de extremidade de serviço porque seus recursos foram excedidos. Você pode retornar informações de erro adicionais por meio do ValueSet. Neste exemplo, usamos uma chave chamada Status para retornar informações de erro mais detalhadas ao chamador.

A chamada para SendResponseAsync retorna o ValueSet para o chamador.

Implantar o aplicativo de serviço e obter o nome da família de pacotes

O provedor de serviços de aplicativo deve ser implantado antes que você possa chamá-lo de um cliente. Você pode implantá-lo selecionando Compilar > Implantar Solução no Visual Studio.

Você também precisará do nome da família de pacotes do provedor de serviços de aplicativo para chamá-lo. Você pode obtê-lo abrindo o arquivo Package.appxmanifest do projeto AppServiceProvider no modo de exibição do designer (clique duas vezes nele no Gerenciador de Soluções). Selecione a guia Empacotamento , copie o valor ao lado de Nome da família do pacote e cole-o em algum lugar como o Bloco de Notas por enquanto.

Escrever um cliente para chamar o serviço de aplicativo

  1. Adicione um novo projeto de aplicativo Universal do Windows em branco à solução com Arquivo > Adicionar > Novo Projeto. Na caixa de diálogo Adicionar Novo Projeto, escolha Aplicativo Visual C# > em Branco Instalado > (Universal Windows) e nomeie-o como ClientApp.

  2. No projeto ClientApp, adicione a seguinte instrução using à parte superior de MainPage.xaml.cs:

    using Windows.ApplicationModel.AppService;
    
  3. Adicione uma caixa de texto chamada textBox e um botão a MainPage.xaml.

  4. Adicione um manipulador de clique de botão para o botão chamado button_Click e adicione a palavra-chave assíncrona à assinatura do manipulador de botão.

  5. Substitua o stub do manipulador de cliques de botão pelo código a seguir. Certifique-se de incluir a declaração de inventoryService campo.

    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;
    }
    

    Substitua o nome da família de pacotes na linha this.inventoryService.PackageFamilyName = "Replace with the package family name"; pelo nome da família de pacotes do projeto AppServiceProvider que você obteve acima em Implantar o aplicativo de serviço e obter o nome da família de pacotes.

    Observação

    Certifique-se de colar o literal da cadeia de caracteres, em vez de colocá-lo em uma variável. Não funcionará se você usar uma variável.

    O código primeiro estabelece uma conexão com o serviço de aplicativo. A conexão permanecerá aberta até que você descarte this.inventoryService. O nome do serviço de aplicativo deve corresponder ao atributo do Name elemento que você adicionou ao arquivo Package.appxmanifest do projeto AppServiceProvider.AppService Neste exemplo, é <uap3:AppService Name="com.microsoft.inventory"/>.

    Um ValueSet nomeado message é criado para especificar o comando que queremos enviar para o serviço de aplicativo. O serviço de aplicativo de exemplo espera que um comando indique qual das duas ações deve ser executada. Obtemos o índice da caixa de texto no aplicativo cliente e, em seguida, chamamos o serviço com o Item comando para obter a descrição do item. Em seguida, fazemos a chamada com o Price comando para obter o preço do item. O texto do botão é definido como o resultado.

    Como AppServiceResponseStatus indica apenas se o sistema operacional foi capaz de conectar a chamada ao serviço de aplicativo, verificamos a Status chave no ValueSet que recebemos do serviço de aplicativo para garantir que ele foi capaz de atender à solicitação.

  6. Defina o projeto ClientApp como o projeto de inicialização (clique com o botão direito do mouse no Gerenciador>de Soluções Definir como Projeto de Inicialização) e execute a solução. Digite o número 1 na caixa de texto e clique no botão. Você deve receber "Cadeira: Preço = 88,99" de volta do serviço.

    Aplicativo de amostra exibindo o preço da cadeira = 88,99

Se a chamada do serviço de aplicativo falhar, verifique o seguinte no projeto ClientApp :

  1. Verifique se o nome da família de pacotes atribuído à conexão do serviço de inventário corresponde ao nome da família de pacotes do aplicativo AppServiceProvider . Veja a linha em button_Click com this.inventoryService.PackageFamilyName = "...";.
  2. No button_Click, verifique se o nome do serviço de aplicativo atribuído à conexão do serviço de inventário corresponde ao nome do serviço de aplicativo no arquivo Package.appxmanifest do AppServiceProvider. Veja: this.inventoryService.AppServiceName = "com.microsoft.inventory";.
  3. Verifique se o aplicativo AppServiceProvider foi implantado. (No Gerenciador de Soluções, clique com o botão direito do mouse na solução e escolha Implantar Solução).

Depurar o serviço de aplicativo

  1. Verifique se a solução é implantada antes da depuração, pois o aplicativo do provedor de serviços de aplicativo deve ser implantado antes que o serviço possa ser chamado. (No Visual Studio, Solução de Implantação de Build>).
  2. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto AppServiceProvider e escolha Propriedades. Na guia Depurar , altere a ação Iniciar para Não iniciar, mas depurar meu código quando ele for iniciado. (Observe que, se você estiver usando C++ para implementar seu provedor de serviços de aplicativo, no Depuração , você alteraria Iniciar aplicativo para Não).
  3. No projeto MyAppService, no arquivo Inventory.cs, defina um ponto de interrupção em OnRequestReceived.
  4. Defina o projeto AppServiceProvider como o projeto de inicialização e pressione F5.
  5. Inicie o ClientApp no menu Iniciar (não no Visual Studio).
  6. Digite o número 1 na caixa de texto e pressione o botão. O depurador será interrompido na chamada do serviço de aplicativo no ponto de interrupção no serviço de aplicativo.

Depurar o cliente

  1. Siga as instruções na etapa anterior para depurar o cliente que chama o serviço de aplicativo.
  2. Inicie o ClientApp no menu Iniciar.
  3. Anexe o depurador ao processo ClientApp.exe (não ao processo ApplicationFrameHost.exe ). (No Visual Studio, escolha Depurar > anexar ao processo....)
  4. No projeto ClientApp, defina um ponto de interrupção em button_Click.
  5. Os pontos de interrupção no cliente e no serviço de aplicativo agora serão atingidos quando você inserir o número 1 na caixa de texto do ClientApp e clicar no botão.

Solução de problemas gerais do serviço de aplicativo

Se você encontrar um status AppUnavailable depois de tentar se conectar a um serviço de aplicativo, verifique o seguinte:

  • Verifique se o projeto do provedor de serviços de aplicativo e o projeto do serviço de aplicativo estão implantados. Ambos precisam ser implantados antes de executar o cliente, caso contrário, o cliente não terá nada para se conectar. Você pode implantar do Visual Studio usando a Solução de Implantação de Build>.
  • No Gerenciador de Soluções, verifique se o projeto do provedor de serviços de aplicativo tem uma referência de projeto a projeto para o projeto que implementa o serviço de aplicativo.
  • Verifique se a <Extensions> entrada e seus elementos filho foram adicionados ao arquivo Package.appxmanifest pertencente ao projeto do provedor de serviços de aplicativo, conforme especificado acima em Adicionar uma extensão de serviço de aplicativo a Package.appxmanifest.
  • Verifique se a cadeia de caracteres AppServiceConnection.AppServiceName em seu cliente que chama o provedor de serviços de aplicativo corresponde ao <uap3:AppService Name="..." /> especificado no arquivo Package.appxmanifest do projeto do provedor de serviços de aplicativo.
  • Verifique se o AppServiceConnection.PackageFamilyName corresponde ao nome da família de pacotes do componente do provedor de serviços de aplicativo, conforme especificado acima em Adicionar uma extensão de serviço de aplicativo a Package.appxmanifest
  • Para serviços de aplicativo fora do proc, como o deste exemplo, valide se o EntryPoint <uap:Extension ...> especificado no elemento do arquivo Package.appxmanifest do projeto do provedor de serviços de aplicativo corresponde ao namespace e ao nome da classe pública que implementa IBackgroundTask em seu projeto de serviço de aplicativo.

Solucionar problemas de depuração

Se o depurador não parar em pontos de interrupção em seu provedor de serviços de aplicativo ou projetos de serviço de aplicativo, verifique o seguinte:

  • Verifique se o projeto do provedor de serviços de aplicativo e o projeto do serviço de aplicativo estão implantados. Ambos precisam ser implantados antes de executar o cliente. Você pode implantá-los do Visual Studio usando a Solução de Implantação de Build>.
  • Certifique-se de que o projeto que você deseja depurar esteja definido como o projeto de inicialização e que as propriedades de depuração desse projeto estejam definidas para não executar o projeto quando F5 for pressionado. Clique com o botão direito do mouse no projeto, clique em Propriedades e, em seguida , em Depurar (ou Depuração em C++). Em C#, altere a ação Iniciar para Não iniciar, mas depurar meu código quando ele for iniciado. Em C++, defina Iniciar Aplicativo como Não.

Comentários

Este exemplo fornece uma introdução à criação de um serviço de aplicativo que é executado como uma tarefa em segundo plano e chamá-lo de outro aplicativo. As principais coisas a serem observadas são:

  • Crie uma tarefa em segundo plano para hospedar o serviço de aplicativo.
  • Adicione a windows.appService extensão ao arquivo Package.appxmanifest do provedor de serviços de aplicativo.
  • Obtenha o nome da família de pacotes do provedor de serviços de aplicativo para que possamos nos conectar a ele do aplicativo cliente.
  • Adicione uma referência de projeto a projeto do provedor de serviços de aplicativo ao projeto do serviço de aplicativo.
  • Use Windows.ApplicationModel.AppService.AppServiceConnection para chamar o serviço.

Código completo para 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();
            }
        }
    }
}