Windows 10开发 - 服务

在本章中,我们将了解UWP应用程序如何为其他通用Windows平台(UWP)应用程序提供帮助或提供服务.实际上,本章是背景执行章节的扩展,是一个特例.

  • 在Windows 10中,应用服务是应用向其他应用提供服务的一种方式或机制.

  • 应用服务在表单中有效后台任务.

  • 前台应用可以在另一个应用中调用应用服务,以便在后台执行任务.

APP Services

应用服务就像网络服务但应用程序Windows 10设备上使用的服务.

通用Windows平台(UWP)应用程序可以通过各种方式与其他UWP应用程序进行交互 :

  • 使用LaunchUriAsync的URI关联

  • 使用LaunchFileAsync的文件关联

  • 使用LaunchUriForResultsAsync启动结果

  • 应用程序服务

  • 当两个应用程序都是前台时使用前三种方式,但是应用程序服务用于后台任务,在这种情况下,客户端应用程序必须位于前台且可用使用App服务.

    应用程序服务在提供非可视服务的应用程序中非常有用,例如条形码扫描器,其中前景应用程序将获取图像并将这些字节发送到应用程序服务以识别条形码.

    要理解所有这些概念,让我们创建一个新的UWP在Microsoft Visual Studio 2015中使用名称 AppServiceProvider 的项目.

    现在在 Package.appmenifest 文件中,添加以下信息.

    APP Services
  • 创建一个可以调用的应用服务前台应用程序,让我们使用 MyAppService 名称将新的 Windows运行时组件项目添加到解决方案中,因为应用程序服务是作为后台任务实现的.

    AppServiceProvider 项目中添加对 MyAppService 项目的引用.

    现在删除 class1.cs 来自 MyAppService 项目的文件,并添加一个带有库存名称的新类,该类将实现 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来创建客户端应用project 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>
  • 以下是请求App服务的按钮单击事件实现.

    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>部署此解决方案;部署解决方案.

    APP服务
  • 以上时间编译并执行代码,您将看到以下窗口.在App服务中,我们刚刚添加了两个项目的信息.因此,您可以输入0或1来获取这些项目的信息.

    APP Services
  • 当您输入0并单击该按钮时,它将运行App服务作为后台任务,并将在文本块上显示项目信息.