Desarrollo de Windows 10: servicios
En este capítulo, aprenderemos cómo las aplicaciones para UWP pueden ayudar o proporcionar servicios a otras aplicaciones de la Plataforma universal de Windows (UWP). En realidad, este capítulo es una extensión del capítuloBackground execution y es un caso especial de ello.
En Windows 10, un servicio de aplicación es una forma o mecanismo para que una aplicación proporcione servicios a otras aplicaciones.
Un servicio de aplicación funciona en forma de tarea en segundo plano.
Las aplicaciones en primer plano pueden llamar a un servicio de aplicaciones en otra aplicación para realizar tareas en segundo plano.
Los servicios de aplicaciones son como los servicios web, pero los servicios de aplicaciones se utilizan en dispositivos con Windows 10.
Las aplicaciones de la Plataforma universal de Windows (UWP) pueden interactuar con otra aplicación para UWP de varias formas:
- Asociación de URI mediante LaunchUriAsync
- Asociación de archivos mediante LaunchFileAsync
- Lanzamiento para resultados usando LaunchUriForResultsAsync
- Servicios de aplicaciones
Las primeras tres formas se utilizan cuando ambas aplicaciones están en primer plano, pero los servicios de aplicaciones se utilizan en background task y en ese caso la aplicación cliente debe estar en primer plano y disponible para usar el servicio de aplicaciones.
Los servicios de aplicaciones son muy beneficiosos en aplicaciones en las que se proporcionan servicios no visuales, por ejemplo, un escáner de código de barras en el que una aplicación en primer plano tomará la imagen y enviará esos bytes a los servicios de la aplicación para identificar el código de barras.
Para comprender todos estos conceptos, creemos un nuevo proyecto para UWP con el nombre AppServiceProvider en Microsoft Visual Studio 2015.
Ahora en el Package.appmenifest archivo, agregue la siguiente información.
Para crear un servicio de aplicaciones, que puede ser invocado por aplicaciones en primer plano, agreguemos un nuevo Windows Runtime Proyecto componente a la solución con MyAppService name, porque los servicios de aplicaciones se implementan como una tarea en segundo plano.
Agregue una referencia al MyAppService proyecto en el AppServiceProvider proyecto.
Ahora borre el class1.cs archivo de MyAppService proyecto y agregue una nueva clase con el nombre del inventario, que implementará el IBackgrounTask interfaz.
los IBackgrounTask la interfaz tiene un solo método “Run” que debe implementarse para la tarea en segundo plano.
public sealed class Inventory : IBackgroundTask {
public void Run(IBackgroundTaskInstance taskInstance) {
}
}
Cuando se crea la tarea en segundo plano, Run() methodse llama y cuando se completa el método Run, se terminan las tareas en segundo plano. Para mantenerse al día en una tarea en segundo plano, para atender solicitudes, el código se aplaza.
El código de los servicios de la aplicación está en OnRequestedReceived(). En este ejemplo, un índice de un artículo de inventario pasa al servicio para recuperar el nombre y el precio del artículo de inventario especificado.
private async void OnRequestReceived(AppServiceConnection sender,
AppServiceRequestReceivedEventArgs args) {
// Get a deferral because we use an awaitable API below to respond to the message
}
A continuación se muestra la implementación completa de la clase Inventory en C #.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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) {
this.backgroundTaskDeferral = taskInstance.GetDeferral();
taskInstance.Canceled += OnTaskCanceled;
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
appServiceconnection = details.AppServiceConnection;
appServiceconnection.RequestReceived += OnRequestReceived;
}
private async void OnRequestReceived(AppServiceConnection sender,
AppServiceRequestReceivedEventArgs args) {
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");
}
}
await args.Request.SendResponseAsync(returnData);
messageDeferral.Complete();
}
private void OnTaskCanceled(IBackgroundTaskInstance sender,
BackgroundTaskCancellationReason reason){
if (this.backgroundTaskDeferral != null) {
// Complete the service deferral.
this.backgroundTaskDeferral.Complete();
}
}
}
}
Creemos una aplicación cliente agregando un nuevo proyecto de UWP en blanco ClientApp y agregue un botón, un cuadro de texto y dos bloques de texto como se muestra a continuación en el archivo XAML.
<Page
x:Class = "ClientApp.MainPage"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "using:ClientApp"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable = "d">
<Grid Background = "{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock HorizontalAlignment = "Left" Text = "Enter Item No."
Margin = "52,40,0,0" TextWrapping = "Wrap"
VerticalAlignment = "Top" Height = "32" Width = "268"/>
<Button x:Name = "button" Content = "Get Info" HorizontalAlignment = "Left"
Margin = "255,96,0,0" VerticalAlignment = "Top" Click = "button_Click"/>
<TextBox x:Name = "textBox" HorizontalAlignment = "Left" Margin = "52,96,0,0"
TextWrapping = "Wrap" VerticalAlignment = "Top" Width = "168"/>
<TextBlock x:Name = "textBlock" HorizontalAlignment = "Left"
Margin = "52,190,0,0" TextWrapping = "Wrap"
VerticalAlignment = "Top" Height = "32" Width = "268"/>
</Grid>
</Page>
A continuación se muestra la implementación del evento de clic de botón en el que se solicitan los servicios de la aplicación.
using System;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The Blank Page item template is documented at
http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace ClientApp {
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page {
private AppServiceConnection inventoryService;
public MainPage() {
this.InitializeComponent();
}
private async void button_Click(object sender, RoutedEventArgs e){
// Add the connection.
if (this.inventoryService == null) {
this.inventoryService = new AppServiceConnection();
this.inventoryService.AppServiceName = "com.microsoft.inventory";
this.inventoryService.PackageFamilyName =
"bb1a8478-8005-46869923-e525ceaa26fc_4sz2ag3dcq60a";
var status = await this.inventoryService.OpenAsync();
if (status != AppServiceConnectionStatus.Success) {
button.Content = "Failed to connect";
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;
}
}
textBlock.Text = result;
}
}
}
Para ejecutar esta aplicación, deberá configurar el ClientApp proyecto para que sea el proyecto de inicio en el Explorador de soluciones y luego implementar esta solución desde Build > Deploy Solución.
Cuando se compile y ejecute el código anterior, verá la siguiente ventana. En los servicios de aplicaciones, acabamos de agregar información de dos elementos. Por lo tanto, puede ingresar 0 o 1 para obtener información de esos elementos.
Cuando ingresa 0 y hace clic en el botón, se ejecutará el servicio de aplicaciones como tarea en segundo plano y mostrará la información del elemento en el textblock.