Windows 10 开发 – 服务
Windows 10 开发 – 服务
在本章中,我们将了解 UWP 应用如何帮助或为另一个通用 Windows 平台 (UWP) 应用程序提供服务。实际上,本章是对后台执行一章的扩展,是它的一个特例。
-
在 Windows 10 中,应用服务是应用向其他应用提供服务的一种方式或机制。
-
应用服务以后台任务的形式工作。
-
前台应用可以调用另一个应用中的应用服务在后台执行任务。
应用服务类似于 Web 服务,但应用服务在 Windows 10 设备上使用。
通用 Windows 平台 (UWP) 应用程序可以通过各种方式与另一个 UWP 应用程序交互 –
- 使用 LaunchUriAsync 的 URI 关联
- 使用 LaunchFileAsync 进行文件关联
- 使用 LaunchUriForResultsAsync 启动结果
- 应用服务
当两个应用程序都在前台时使用前三种方式,但应用服务在后台任务中使用,在这种情况下,客户端应用程序必须在前台并且可以使用应用服务。
应用程序服务在提供非视觉服务的应用程序中非常有用,例如条形码扫描仪,其中前台应用程序将获取图像并将这些字节发送到应用程序服务以识别条形码。
为了理解所有这些概念,让我们在 Microsoft Visual Studio 2015 中创建一个名为AppServiceProvider的新 UWP 项目。
现在在Package.appmenifest文件中,添加以下信息。
要创建可由前台应用程序调用的应用服务,让我们向解决方案中添加一个名为MyAppService的新Windows 运行时组件项目,因为应用服务是作为后台任务实现的。
在AppServiceProvider项目中添加对MyAppService项目的引用。
现在从MyAppService项目中删除class1.cs文件并添加一个具有清单名称的新类,它将实现IBackgrounTask接口。
所述IBackgrounTask接口只有一个方法“运行”,其需要用于后台任务来实现。
public sealed class Inventory : IBackgroundTask { public void Run(IBackgroundTaskInstance taskInstance) { } }
创建后台任务时,调用Run() 方法,当 Run 方法完成时,则终止后台任务。为了保持后台任务,服务请求,代码需要延迟。
应用服务代码位于OnRequestedReceived() 中。在此示例中,库存项目的索引传递给服务,以检索指定库存项目的名称和价格。
private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { // Get a deferral because we use an awaitable API below to respond to the message }
下面给出了在 C# 中 Inventory 类的完整实现。
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(); } } } }
让我们通过添加一个新的空白 UWP 项目ClientApp来创建一个客户端应用程序,并在 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>
下面给出了请求应用服务的按钮单击事件实现。
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; } } }
要运行此应用程序,您需要在解决方案资源管理器中将ClientApp项目设置为启动项目,然后从Build > Deploy Solution部署此解决方案。
上述代码编译执行后,会看到如下窗口。在应用服务中,我们刚刚添加了两个项目的信息。因此,您可以输入 0 或 1 来获取这些项目的信息。
当您输入 0 并单击按钮时,它将运行 App 服务作为后台任务,并将在textblock上显示项目信息。