Crear y usar un servicio de aplicaciones

Importante

Los listados de código de este tema son solo de C#. Para ver una aplicación de ejemplo de App Service en C++/WinRT , así como C#, consulte Aplicación de ejemplo de App Service.

Los servicios de aplicaciones son aplicaciones para UWP que proporcionan servicios a otras aplicaciones para UWP. Son análogos a los servicios web, en un dispositivo. Un servicio de aplicaciones se ejecuta como tarea en segundo plano en la aplicación host y puede proporcionar su servicio a otras aplicaciones. Por ejemplo, un servicio de aplicaciones podría proporcionar un servicio de escáner de códigos de barras que podrían usar otras aplicaciones. O quizás un conjunto de aplicaciones Enterprise tiene un servicio de aplicaciones de revisión ortográfica común que está disponible para las otras aplicaciones del conjunto. Los servicios de aplicaciones permiten crear servicios sin interfaz de usuario a los que las aplicaciones pueden llamar en el mismo dispositivo y a partir de Windows 10, versión 1607, en dispositivos remotos.

A partir de Windows 10, versión 1607, puedes crear servicios de aplicación que se ejecutan en el mismo proceso que la aplicación host. Este artículo se centra en la creación y consumo de un servicio de aplicaciones que se ejecuta en un proceso en segundo plano independiente. Consulte Conversión de un servicio de aplicaciones para que se ejecute en el mismo proceso que su aplicación host para obtener más información sobre cómo ejecutar un servicio de aplicaciones en el mismo proceso que el proveedor.

Crear un proyecto nuevo de proveedor de servicios de aplicaciones

En este procedimiento, lo crearemos todo en una solución para hacerlo más sencillo.

  1. En Visual Studio 2015 o posterior, cree un nuevo proyecto de aplicación para UWP y asígnelo el nombre AppServiceProvider.

    1. Seleccione Archivo > nuevo > proyecto...
    2. En el cuadro de diálogo Crear un nuevo proyecto , seleccione Aplicación vacía (Windows universal) C#. Esta será la aplicación que hace que el servicio de aplicaciones esté disponible para otras aplicaciones para UWP.
    3. Haga clic en Siguiente y, a continuación, asigne al proyecto el nombre AppServiceProvider, elija una ubicación para él y, a continuación, haga clic en Crear.
  2. Cuando se le pida que seleccione una versión dedestino y mínima para el proyecto, seleccione al menos 10.0.14393. Si quiere usar el nuevo atributo SupportsMultipleInstances , debe usar Visual Studio 2017 o Visual Studio 2019 y tener como destino 10.0.15063 (Windows 10 Creators Update) o posterior.

Adición de una extensión de App Service a Package.appxmanifest

En el proyecto AppServiceProvider , abra el archivo Package.appxmanifest en un editor de texto:

  1. Haga clic con el botón derecho en el Explorador de soluciones.
  2. Seleccione Abrir con.
  3. Seleccione Editor XML (texto).

Agregue la siguiente AppService extensión dentro del <Application> elemento . Este ejemplo anuncia el servicio com.microsoft.inventory y es lo que identifica a esta aplicación como un proveedor de servicios de aplicaciones. El servicio real se implementará como una tarea en segundo plano. El proyecto de App Service expone el servicio a otras aplicaciones. Se recomienda usar un estilo inverso de nombre de dominio para el nombre del servicio.

Tenga en cuenta que el xmlns:uap4 prefijo del espacio de nombres y el uap4:SupportsMultipleInstances atributo solo son válidos si el destino es Windows SDK versión 10.0.15063 o posterior. Puede quitarlos de forma segura si tiene como destino versiones anteriores del SDK.

Nota:

Para ver una aplicación de ejemplo de App Service en C++/WinRT , así como C#, consulte Aplicación de ejemplo de 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>

El Category atributo identifica esta aplicación como proveedor de servicios de aplicaciones.

El EntryPoint atributo identifica la clase calificada del espacio de nombres que implementa el servicio, que implementaremos a continuación.

El SupportsMultipleInstances atributo indica que cada vez que se llama al servicio de aplicaciones que debe ejecutarse en un nuevo proceso. Esto no es necesario, pero está disponible si necesita esa funcionalidad y tiene como destino el SDK 10.0.15063 (Windows 10 Creators Update) o posterior. También debe estar precedido por el uap4 espacio de nombres .

Crear el servicio de aplicaciones

  1. Un servicio de aplicaciones se puede implementar como una tarea en segundo plano. Esto permite que una aplicación en primer plano invoque un servicio de aplicaciones en otra aplicación. Para crear un servicio de aplicaciones como tarea en segundo plano, agregue un nuevo proyecto de componente de Windows Runtime a la solución (Archivo > agregar > nuevo proyecto) denominada MyAppService. En el cuadro de diálogo Agregar nuevo proyecto, elija Instalado > Visual C# > Windows Runtime Componente (Windows universal).

  2. En el proyecto AppServiceProvider, agregue una referencia de proyecto a proyecto al nuevo proyecto MyAppService (en el Explorador de soluciones, haga clic con el botónderecho en el proyecto > AppServiceProvider Agregarsoluciónproyectos> dereferencia>>, seleccione MyAppService>Ok). Este paso es fundamental porque, si no agrega la referencia, el servicio de aplicaciones no se conectará en tiempo de ejecución.

  3. En el proyecto MyAppService , agregue las siguientes instrucciones using a la parte superior de Class1.cs:

    using Windows.ApplicationModel.AppService;
    using Windows.ApplicationModel.Background;
    using Windows.Foundation.Collections;
    
  4. Cambie el nombre de Class1.cs a Inventory.cs y reemplace el código auxiliar de Class1 por una nueva clase de tarea en segundo plano denominada 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();
            }
        }
    }
    

    Esta clase es el lugar donde el servicio de aplicaciones hará su trabajo.

    Se llama a Run cuando se crea la tarea en segundo plano. Dado que las tareas en segundo plano finalizan una vez finalizada la ejecución , el código saca un aplazamiento para que la tarea en segundo plano permanezca al día para atender las solicitudes. Un servicio de aplicaciones que se implementa como una tarea en segundo plano permanecerá activo durante unos 30 segundos después de recibir una llamada a menos que se llame de nuevo dentro de ese período de tiempo o se quite un aplazamiento. Si el servicio de aplicaciones se implementa en el mismo proceso que el autor de la llamada, la duración del servicio de aplicaciones está vinculada a la duración del autor de la llamada.

    La duración del servicio de aplicaciones depende del autor de la llamada:

    • Si el autor de la llamada está en primer plano, la duración del servicio de aplicaciones es la misma que la del autor de la llamada.
    • Si el autor de la llamada está en segundo plano, app service obtiene 30 segundos de ejecución. Quitar un aplazamiento proporciona un tiempo adicional de 5 segundos.

    Se llama a OnTaskCanceled cuando se cancela la tarea. La tarea se cancela cuando la aplicación cliente elimina AppServiceConnection, la aplicación cliente se suspende, el sistema operativo se apaga o se suspende, o el sistema operativo se queda sin recursos para ejecutar la tarea.

Escribir el código para el servicio de aplicaciones

OnRequestReceived es donde va el código del servicio de aplicaciones. Reemplace el código auxiliar OnRequestReceived en Inventory.cs de MyAppService por el código de este ejemplo. Este código obtiene un índice para un elemento de inventario y, junto con una cadena de comandos, lo pasa al servicio para recuperar el nombre y el precio del elemento de inventario especificado. Para sus propios proyectos, agregue código de control de errores.

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

Tenga en cuenta que OnRequestReceived es asincrónico porque realizamos una llamada de método await a SendResponseAsync en este ejemplo.

Se toma un aplazamiento para que el servicio pueda usar métodos asincrónicos en el controlador OnRequestReceived . Garantiza que la llamada a OnRequestReceived no se complete hasta que haya terminado de procesar el mensaje. SendResponseAsync envía el resultado al autor de la llamada. SendResponseAsync no indica la finalización de la llamada. Es la finalización del aplazamiento que indica a SendMessageAsync que OnRequestReceived se ha completado. La llamada a SendResponseAsync se ajusta en un bloque try/finally porque debe completar el aplazamiento incluso si SendResponseAsync produce una excepción.

Los servicios de aplicaciones usan objetos ValueSet para intercambiar información. El tamaño de los datos que se pueden pasar solo está limitado por los recursos del sistema. No hay claves predefinidas para su uso en el elemento ValueSet. Debes determinar qué valores clave usarás para definir el protocolo del servicio de aplicaciones. Debes escribir el llamador teniendo ese protocolo presente. En este ejemplo, hemos elegido una clave denominada Command que tiene un valor que indica si queremos que el servicio de aplicaciones proporcione el nombre del elemento de inventario o su precio. El índice del nombre del inventario se almacena en la ID clave. El valor devuelto se almacena en la Result clave.

Se devuelve al llamador una enumeración AppServiceClosedStatus para indicar si la llamada al servicio de aplicaciones se ha realizado correctamente o no. Un ejemplo de cómo se puede producir un error en la llamada al servicio de aplicaciones es si el sistema operativo anula el punto de conexión de servicio porque se han superado sus recursos. Puedes devolver información adicional sobre errores a través de ValueSet. En este ejemplo, usamos una clave denominada Status para devolver información de error más detallada al autor de la llamada.

La llamada a SendResponseAsync devuelve el elemento ValueSet al llamador.

Implementar el servicio de aplicaciones y obtener el nombre de familia de paquete

El proveedor de servicios de aplicaciones debe implementarse para poder llamarlo desde un cliente. Para implementarla, seleccione Compilar > implementación de la solución en Visual Studio.

También necesitará el nombre de familia del paquete del proveedor de servicios de aplicaciones para llamarlo. Para obtenerlo, abra el archivo Package.appxmanifest del proyecto AppServiceProvider en la vista del diseñador (haga doble clic en él en el Explorador de soluciones). Seleccione la pestaña Empaquetado , copie el valor junto a Nombre de familia del paquete y péguelo en algún lugar como el Bloc de notas por ahora.

Escribir un cliente para llamar al servicio de aplicaciones

  1. Agregue un nuevo proyecto de aplicación universal de Windows en blanco a la solución con El archivo > Agregar > nuevo proyecto. En el cuadro de diálogo Agregar nuevo proyecto , elija Instalado > Visual C# > Aplicación vacía (Windows universal) y asígnele el nombre ClientApp.

  2. En el proyecto ClientApp , agregue la siguiente instrucción using a la parte superior de MainPage.xaml.cs:

    using Windows.ApplicationModel.AppService;
    
  3. Agregue un cuadro de texto denominado textBox y un botón a MainPage.xaml.

  4. Agregue un controlador de clic de botón para el botón denominado button_Click y agregue la palabra clave asincrónica a la firma del controlador de botones.

  5. Reemplaza el código auxiliar del controlador de clic del botón por el siguiente código. Asegúrate de incluir la declaración de campo 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;
    }
    

    Reemplace el nombre de familia del paquete en la línea this.inventoryService.PackageFamilyName = "Replace with the package family name"; por el nombre de familia del paquete del proyecto AppServiceProvider que obtuvo anteriormente en Implementar la aplicación de servicio y obtener el nombre de familia del paquete.

    Nota:

    Asegúrese de pegar en el literal de cadena, en lugar de colocarlo en una variable. No funcionará si usa una variable.

    En primer lugar, el código establece una conexión con el servicio de aplicaciones. La conexión permanecerá abierta hasta que elimine this.inventoryService. El nombre del servicio de aplicaciones debe coincidir con el AppService atributo del Name elemento que agregó al archivo Package.appxmanifest del proyecto AppServiceProvider. En este ejemplo, es <uap3:AppService Name="com.microsoft.inventory"/>.

    Se crea un valueSet denominado message para especificar el comando que queremos enviar al servicio de aplicaciones. El servicio de aplicaciones de ejemplo espera un comando para indicar qué dos acciones realizar. Obtenemos el índice del cuadro de texto de la aplicación cliente y, a continuación, llamamos al servicio con el Item comando para obtener la descripción del elemento. A continuación, realizamos la llamada con el Price comando para obtener el precio del artículo. El texto del botón se define en el resultado.

    Dado que AppServiceResponseStatus solo indica si el sistema operativo pudo conectar la llamada al servicio de aplicaciones, comprobamos la Status clave en valueSet que recibimos del servicio de aplicaciones para asegurarse de que pudo cumplir la solicitud.

  6. Establezca el proyecto ClientApp en el proyecto de inicio (haga clic con el botón derecho en él en el Explorador de soluciones>Set como proyecto de inicio) y ejecute la solución. Escribe el número 1 en el cuadro de texto y haz clic en el botón. El servicio debería devolver "Chair : Price = 88.99".

    aplicación de muestra que muestra el precio de la silla=88.99

Si se produce un error en la llamada de App Service, compruebe lo siguiente en el proyecto ClientApp :

  1. Compruebe que el nombre de familia del paquete asignado a la conexión del servicio de inventario coincide con el nombre de familia del paquete de la aplicación AppServiceProvider . Vea la línea de button_Click con this.inventoryService.PackageFamilyName = "...";.
  2. En button_Click, compruebe que el nombre del servicio de aplicaciones asignado a la conexión del servicio de inventario coincide con el nombre del servicio de aplicaciones en el archivo Package.appxmanifest de AppServiceProvider. Consulta: this.inventoryService.AppServiceName = "com.microsoft.inventory";.
  3. Asegúrese de que se ha implementado la aplicación AppServiceProvider . (En el Explorador de soluciones, haga clic con el botón derecho en la solución y elija Implementar solución).

Depurar el servicio de aplicaciones

  1. Asegúrese de que la solución se implementa antes de depurar porque la aplicación del proveedor de servicios de aplicaciones debe implementarse antes de que se pueda llamar al servicio. (En Visual Studio, Compilar > Implementar solución).
  2. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto AppServiceProvider y elija Propiedades. Desde la pestaña Depurar cambia Acción de inicio a No iniciar, pero depurar mi código al empezar. (Tenga en cuenta que si usaba C++ para implementar el proveedor de servicios de aplicaciones, en la pestaña Depuración cambiaría Iniciar aplicación a No).
  3. En el proyecto MyAppService , en el archivo Inventory.cs , establezca un punto de interrupción en OnRequestReceived.
  4. Establezca el proyecto AppServiceProvider para que sea el proyecto de inicio y presione F5.
  5. Inicie ClientApp desde el menú Inicio (no desde Visual Studio).
  6. Escribe el número 1 en el cuadro de texto y presiona el botón. El depurador se detendrá en la llamada al servicio de aplicaciones en el punto de interrupción del servicio de aplicaciones.

Depurar el cliente

  1. Siga las instrucciones del paso anterior para depurar el cliente que llama al servicio de aplicaciones.
  2. Inicie ClientApp desde el menú Inicio.
  3. Adjunte el depurador al proceso deClientApp.exe (no al proceso deApplicationFrameHost.exe ). (En Visual Studio, elige Depurar > Asociar al proceso…)
  4. En el proyecto ClientApp , establezca un punto de interrupción en button_Click.
  5. Los puntos de interrupción tanto en el cliente como en el servicio de aplicaciones ahora se alcanzarán cuando escriba el número 1 en el cuadro de texto clientApp y haga clic en el botón.

Solución de problemas generales de App Service

Si encuentra un estado AppUnavailable después de intentar conectarse a un servicio de aplicaciones, compruebe lo siguiente:

  • Asegúrese de que el proyecto del proveedor de app service y el proyecto de App Service estén implementados. Ambos deben implementarse antes de ejecutar el cliente porque, de lo contrario, el cliente no tendrá nada al que conectarse. Puede realizar la implementación desde Visual Studio mediante Compilar>implementación de la solución.
  • En el Explorador de soluciones, asegúrese de que el proyecto del proveedor de servicios de aplicaciones tenga una referencia de proyecto a proyecto al proyecto que implementa el servicio de aplicaciones.
  • Compruebe que la <Extensions> entrada y sus elementos secundarios se han agregado al archivo Package.appxmanifest que pertenece al proyecto del proveedor de servicios de aplicaciones, tal y como se especificó anteriormente en Agregar una extensión de App Service a Package.appxmanifest.
  • Asegúrese de que la cadena AppServiceConnection.AppServiceName del cliente que llama al proveedor de servicios de aplicaciones coincide con el <uap3:AppService Name="..." /> especificado en el archivo Package.appxmanifest del proyecto del proveedor de servicios de aplicaciones.
  • Asegúrese de que AppServiceConnection.PackageFamilyName coincida con el nombre de familia del paquete del componente del proveedor de servicios de aplicaciones, tal y como se especificó anteriormente en Agregar una extensión de App Service a Package.appxmanifest.
  • Para servicios de aplicaciones fuera de proceso, como el de este ejemplo, valide que el EntryPoint especificado en el <uap:Extension ...> elemento del archivo Package.appxmanifest del proyecto del proveedor de servicios de aplicaciones coincida con el espacio de nombres y el nombre de clase de la clase pública que implementa IBackgroundTask en el proyecto de App Service.

Solución de problemas de depuración

Si el depurador no se detiene en los puntos de interrupción del proveedor de app service o los proyectos de App Service, compruebe lo siguiente:

  • Asegúrese de que el proyecto del proveedor de app service y el proyecto de App Service estén implementados. Ambos deben implementarse antes de ejecutar el cliente. Puede implementarlos desde Visual Studio mediante Compilar>implementación de la solución.
  • Asegúrese de que el proyecto que desea depurar está establecido como proyecto de inicio y de que las propiedades de depuración de ese proyecto están establecidas para no ejecutar el proyecto cuando se presiona F5 . Haga clic con el botón derecho en el proyecto, haga clic en Propiedades y, después, en Depurar (o Depurar en C++). En C#, cambie la acción Iniciar a No iniciar, pero depurar mi código cuando se inicie. En C++, establezca Iniciar aplicación en No.

Comentarios

En este ejemplo se proporciona una introducción a la creación de un servicio de aplicaciones que se ejecuta como una tarea en segundo plano y se llama desde otra aplicación. Los aspectos clave que se deben tener en cuenta son:

  • Cree una tarea en segundo plano para hospedar el servicio de aplicaciones.
  • Agregue la windows.appService extensión al archivo Package.appxmanifest del proveedor de servicios de aplicaciones.
  • Obtenga el nombre de familia del paquete del proveedor de servicios de aplicaciones para poder conectarse a él desde la aplicación cliente.
  • Agregue una referencia de proyecto a proyecto desde el proyecto del proveedor de servicios de aplicaciones al proyecto de App Service.
  • Use Windows.ApplicationModel.AppService.AppServiceConnection para llamar al servicio.

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