Crear y usar un servicio de aplicaciones

Importante

Los listados de código de este tema son solo 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 de aplicaciones. 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 aplicaciones que se ejecuten 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.

Creación de un nuevo proyecto de proveedor de servicios de aplicaciones

En este procedimiento, crearemos todo en una solución para simplificar.

  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 app service 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 un destino y una versión 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 (Actualización de Windows 10 para creadores) 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 . En este ejemplo se anuncia el com.microsoft.inventory servicio y es lo que identifica esta aplicación como 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 de nombre de dominio inverso 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 tiene como destino 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 (Actualización de Windows 10 para creadores) o posterior. También debe estar precedido por el uap4 espacio de nombres.

Creación del App Service

  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 una 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 > Componente de Windows Runtime de Visual C# > (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ón derecho en el proyecto> AppServiceProvider Agregar solución Proyectos>>de referencia>, seleccione MyAppService>Ok). Este paso es fundamental porque si no agrega la referencia, app service 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 donde app service realizará su trabajo.

    Se llama a Run cuando se crea la tarea en segundo plano. Dado que las tareas en segundo plano finalizan una vez completada la ejecución, el código toma 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 vuelva a llamar 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 para ejecutarse. 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.

Escritura del 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 el Inventory.cs de MyAppService por el código de este ejemplo. Este código obtiene un índice para un elemento de inventario y lo pasa, junto con una cadena de comandos, 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 aunque SendResponseAsync produzca una excepción.

Los servicios de aplicaciones usan objetos ValueSet para intercambiar información. El tamaño de los datos que puede pasar solo está limitado por los recursos del sistema. No hay claves predefinidas que pueda usar en valueSet. Debe determinar qué valores de clave usará para definir el protocolo para el servicio de aplicaciones. El autor de la llamada debe escribirse teniendo en cuenta ese protocolo. 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 artículo de inventario o su precio. El índice del nombre del inventario se almacena en la ID clave. El valor devuelto se almacena bajo la Result clave.

Se devuelve una enumeración AppServiceClosedStatus al autor de la llamada para indicar si la llamada al servicio de aplicaciones se realizó correctamente o no. Un ejemplo de cómo se podría 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. Puede devolver información adicional de error a través de ValueSet. En este ejemplo, se usa una clave denominada Status para devolver información de error más detallada al autor de la llamada.

La llamada a SendResponseAsync devuelve valueSet al autor de la llamada.

Implementación de la aplicación de servicio y obtención del nombre de familia del paquete

El proveedor de servicios de aplicaciones debe implementarse para poder llamarlo desde un cliente. Para implementarla, seleccione Compilar > implementación de 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 de paquetes y péguelo en algún lugar como el Bloc de notas por ahora.

Escritura de 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 archivo > Agregar > nuevo proyecto. En el cuadro de diálogo Agregar nuevo proyecto , elija Instalado > Visual C# > Aplicación en blanco (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. Reemplace el código auxiliar del controlador de clics del botón por el código siguiente. Asegúrese de incluir la inventoryService declaración de 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;
    }
    

    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.

    El código establece primero 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 atributo del Name elemento que agregó al archivo Package.appxmanifest del proyecto AppServiceProvider.AppService En este ejemplo, es <uap3:AppService Name="com.microsoft.inventory"/>.

    Se crea un objeto 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 cuál de las dos acciones que se van a 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 establece 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 como proyecto de inicio (haga clic con el botón derecho en el Explorador de soluciones> Set como proyecto de inicio) y ejecute la solución. Escriba el número 1 en el cuadro de texto y haga clic en el botón. Debería obtener "Silla : Precio = 88.99" de vuelta del servicio.

    aplicación de ejemplo que muestra el precio de 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 en 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. Vea: this.inventoryService.AppServiceName = "com.microsoft.inventory";.
  3. Asegúrese de que se ha implementado la aplicación AppServiceProvider . (En Explorador de soluciones, haga clic con el botón derecho en la solución y elija Implementar solución).

Depuración del 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 > implementación de la solución).
  2. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto AppServiceProvider y elija Propiedades. En la pestaña Depurar , cambie la acción Iniciar a No iniciar, pero depure mi código cuando se inicie. (Tenga en cuenta que, si estaba usando C++ para implementar el proveedor de servicios de aplicaciones, desde Pestaña Depuración que 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. Escriba el número 1 en el cuadro de texto y presione el botón. El depurador se detendrá en la llamada de App Service 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 de ClientApp.exe (no al proceso de ApplicationFrameHost.exe ). (En Visual Studio, elija Depurar > Adjuntar al proceso....)
  4. En el proyecto ClientApp , establezca un punto de interrupción en button_Click.
  5. Ahora se alcanzarán los puntos de interrupción tanto en el cliente como en el servicio de aplicaciones cuando escriba el número 1 en el cuadro de texto de 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 servicios de aplicaciones 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 implementar 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 coincide 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 coincide 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 puntos de interrupción en los proyectos de app Service Provider o App Service, compruebe lo siguiente:

  • Asegúrese de que el proyecto del proveedor de servicios de aplicaciones 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, a continuación , en Depurar (o Depurar en C++). En C#, cambie la acción Iniciar a No iniciar, pero depure 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. Las principales cosas que hay que 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();
            }
        }
    }
}