Entrainement
Parcours d’apprentissage
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Ce navigateur n’est plus pris en charge.
Effectuez une mise à niveau vers Microsoft Edge pour tirer parti des dernières fonctionnalités, des mises à jour de sécurité et du support technique.
Important
Les listes de code de cette rubrique sont C# uniquement. Pour obtenir un exemple d’application App Service en C++/WinRT et C#, consultez l’exemple d’application App Service.
Les services d’application sont des applications UWP qui fournissent des services à d’autres applications UWP. Ils sont analogues aux services web, sur un appareil. Un service d’application s’exécute sous forme de tâche en arrière-plan dans l’application hôte et peut fournir son service à d’autres applications. Par exemple, un service d’application peut fournir un service de scanneur de code-barres que d’autres applications peuvent utiliser. Ou peut-être qu’une suite d’applications Enterprise dispose d’un service commun de vérification orthographique accessible aux autres applications de la suite. Les services d’application vous permettent de créer des services sans interface utilisateur que les applications peuvent appeler sur le même appareil et à partir de Windows 10, version 1607, sur des appareils distants.
À compter de Windows 10, version 1607, vous pouvez créer des services d’application qui s’exécutent dans le même processus que l’application hôte. Cet article se concentre sur la création et la consommation d’un service d’application qui s’exécute dans un processus en arrière-plan distinct. Pour plus d’informations sur l’exécution d’un service d’application, consultez Convertir un service d’application pour qu’il s’exécute dans le même processus que le fournisseur.
Dans ce guide pratique, nous allons créer tout dans une solution pour simplifier.
Dans Visual Studio 2015 ou version ultérieure, créez un projet d’application UWP et nommez-le AppServiceProvider.
Lorsque vous êtes invité à sélectionner une version cible et minimale pour le projet, sélectionnez au moins 10.0.14393. Si vous souhaitez utiliser le nouvel attribut SupportsMultipleInstances, vous devez utiliser Visual Studio 2017 ou Visual Studio 2019 et cibler 10.0.15063 (Mise à jour Windows 10 Créateurs) ou version ultérieure.
Dans le projet AppServiceProvider , ouvrez le fichier Package.appxmanifest dans un éditeur de texte :
Ajoutez l’extension suivante AppService
à l’intérieur de l’élément <Application>
. Cet exemple publie le com.microsoft.inventory
service et identifie cette application en tant que fournisseur de services d’application. Le service réel sera implémenté en tant que tâche en arrière-plan. Le projet App Service expose le service à d’autres applications. Nous vous recommandons d’utiliser un style de nom de domaine inverse pour le nom du service.
Notez que le xmlns:uap4
préfixe d’espace de noms et l’attribut uap4:SupportsMultipleInstances
sont valides uniquement si vous ciblez le SDK Windows version 10.0.15063 ou ultérieure. Vous pouvez les supprimer en toute sécurité si vous ciblez des versions antérieures du Kit de développement logiciel (SDK).
Notes
Pour obtenir un exemple d’application App Service en C++/WinRT et C#, consultez l’exemple d’application 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>
L’attribut Category
identifie cette application en tant que fournisseur de services d’application.
L’attribut EntryPoint
identifie la classe qualifiée d’espace de noms qui implémente le service, que nous allons implémenter ensuite.
L’attribut SupportsMultipleInstances
indique que chaque fois que le service d’application est appelé, il doit s’exécuter dans un nouveau processus. Cela n’est pas obligatoire, mais est disponible si vous avez besoin de cette fonctionnalité et ciblez le SDK 10.0.15063 (Mise à jour Windows 10 Créateurs) ou version ultérieure. Elle doit également être précédée par l’espace uap4
de noms.
Un service d’application peut être implémenté en tant que tâche en arrière-plan. Cela permet à une application de premier plan d’appeler un service d’application dans une autre application. Pour créer un service d’application en tant que tâche en arrière-plan, ajoutez un nouveau projet de composant Windows Runtime à la solution (Ajouter > > un nouveau projet) nommé MyAppService. Dans la boîte de dialogue Ajouter un nouveau projet , choisissez Composant > Windows Runtime Visual C# > installé (Windows universel).
Dans le projet AppServiceProvider, ajoutez une référence de projet à projet au nouveau projet MyAppService (dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet AppServiceProvider Ajouter>>une solution de projets>> de référence, sélectionnez MyAppService>OK). Cette étape est essentielle, car si vous n’ajoutez pas la référence, le service d’application ne se connecte pas au moment de l’exécution.
Dans le projet MyAppService, ajoutez les instructions using suivantes en haut de Class1.cs :
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.Foundation.Collections;
Renommez Class1.cs en Inventory.cs, puis remplacez le code stub pour Class1 par une nouvelle classe de tâche en arrière-plan nommée 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();
}
}
}
Cette classe est l’endroit où le service d’application fera son travail.
L’exécution est appelée lorsque la tâche en arrière-plan est créée. Étant donné que les tâches en arrière-plan sont arrêtées une fois l’exécution terminée, le code supprime un report afin que la tâche en arrière-plan reste à jour pour traiter les demandes. Un service d’application implémenté en tant que tâche en arrière-plan reste actif pendant environ 30 secondes après qu’il reçoit un appel, sauf s’il est appelé à nouveau dans cette fenêtre de temps ou qu’un report est supprimé. Si le service d’application est implémenté dans le même processus que l’appelant, la durée de vie du service d’application est liée à la durée de vie de l’appelant.
La durée de vie du service d’application dépend de l’appelant :
OnTaskCanceled est appelé lorsque la tâche est annulée. La tâche est annulée lorsque l’application cliente supprime AppServiceConnection, l’application cliente est suspendue, le système d’exploitation est arrêté ou en veille, ou le système d’exploitation manque de ressources pour exécuter la tâche.
OnRequestReceived est l’emplacement où se trouve le code du service d’application. Remplacez le stub OnRequestReceived dans le Inventory.cs myAppService par le code de cet exemple. Ce code obtient un index pour un élément d’inventaire et le transmet, ainsi qu’une chaîne de commande, au service pour récupérer le nom et le prix de l’élément d’inventaire spécifié. Pour vos propres projets, ajoutez du code de gestion des erreurs.
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();
}
}
Notez que OnRequestReceived est asynchrone , car nous effectuons un appel de méthode awaitable à SendResponseAsync dans cet exemple.
Un report est effectué afin que le service puisse utiliser des méthodes asynchrones dans le gestionnaire OnRequestReceived . Il garantit que l’appel à OnRequestReceived n’est pas terminé tant qu’il n’a pas terminé de traiter le message. SendResponseAsync envoie le résultat à l’appelant. SendResponseAsync ne signale pas l’achèvement de l’appel. Il s’agit de l’achèvement du report qui signale à SendMessageAsync que OnRequestReceived a terminé. L’appel à SendResponseAsync est encapsulé dans un bloc try/finally, car vous devez terminer le report même si SendResponseAsync lève une exception.
Les services d’application utilisent des objets ValueSet pour échanger des informations. La taille des données que vous pouvez transmettre n’est limitée que par les ressources système. Il n’existe aucune clé prédéfinie à utiliser dans votre ValueSet. Vous devez déterminer les valeurs clés que vous utiliserez pour définir le protocole de votre service d’application. L’appelant doit être écrit à l’esprit avec ce protocole. Dans cet exemple, nous avons choisi une clé nommée Command
qui a une valeur qui indique si le service d’application doit fournir le nom de l’élément d’inventaire ou son prix. L’index du nom d’inventaire est stocké sous la ID
clé. La valeur de retour est stockée sous la Result
clé.
Une énumération AppServiceClosedStatus est retournée à l’appelant pour indiquer si l’appel au service d’application a réussi ou échoué. Par exemple, l’appel au service d’application peut échouer si le système d’exploitation abandonne le point de terminaison de service, car ses ressources ont été dépassées. Vous pouvez retourner des informations d’erreur supplémentaires via ValueSet. Dans cet exemple, nous utilisons une clé nommée Status
pour renvoyer des informations d’erreur plus détaillées à l’appelant.
L’appel à SendResponseAsync retourne ValueSet à l’appelant.
Le fournisseur app service doit être déployé avant de pouvoir l’appeler à partir d’un client. Vous pouvez le déployer en sélectionnant Build > Deploy Solution dans Visual Studio.
Vous aurez également besoin du nom de famille de packages du fournisseur App Service pour l’appeler. Vous pouvez l’obtenir en ouvrant le fichier Package.appxmanifest du projet AppServiceProvider dans l’affichage concepteur (double-cliquez dessus dans le Explorateur de solutions). Sélectionnez l’onglet Empaquetage, copiez la valeur en regard du nom de la famille du package et collez-la quelque part comme le Bloc-notes pour l’instant.
Ajoutez un nouveau projet d’application windows universelle vide à la solution avec Fichier > Ajouter > un nouveau projet. Dans la boîte de dialogue Ajouter un nouveau projet, choisissez Application > vide Visual C# > installée (Windows universel) et nommez-la ClientApp.
Dans le projet ClientApp, ajoutez l’instruction using suivante en haut de MainPage.xaml.cs :
using Windows.ApplicationModel.AppService;
Ajoutez une zone de texte appelée zone de texte et un bouton à MainPage.xaml.
Ajoutez un gestionnaire de clics de bouton pour le bouton appelé button_Click, puis ajoutez le mot clé asynchrone à la signature du gestionnaire de boutons.
Remplacez le stub de votre gestionnaire de clics de bouton par le code suivant. Veillez à inclure la déclaration de inventoryService
champ.
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;
}
Remplacez le nom de la famille de packages dans la ligne this.inventoryService.PackageFamilyName = "Replace with the package family name";
par le nom de famille de packages du projet AppServiceProvider que vous avez obtenu ci-dessus dans Déployer l’application de service et obtenir le nom de la famille de packages.
Notes
Veillez à coller dans le littéral de chaîne, plutôt que de le placer dans une variable. Cela ne fonctionnera pas si vous utilisez une variable.
Le code établit d’abord une connexion avec le service d’application. La connexion reste ouverte jusqu’à ce que vous disposiez this.inventoryService
. Le nom du service d’application doit correspondre à l’attribut de l’élément AppService
que vous avez ajouté au fichier Package.appxmanifest du projet AppServiceProvider.Name
Dans cet exemple, il s’agit de <uap3:AppService Name="com.microsoft.inventory"/>
.
Un jeu de valeurs nommé message
est créé pour spécifier la commande que nous voulons envoyer au service d’application. L’exemple d’app service s’attend à ce qu’une commande indique les deux actions à entreprendre. Nous obtenons l’index à partir de la zone de texte de l’application cliente, puis appelons le service avec la Item
commande pour obtenir la description de l’élément. Ensuite, nous effectuons l’appel avec la Price
commande pour obtenir le prix de l’article. Le texte du bouton est défini sur le résultat.
Étant donné que AppServiceResponseStatus indique uniquement si le système d’exploitation a pu connecter l’appel au service d’application, nous vérifions la Status
clé du ValueSet que nous recevons du service d’application pour vous assurer qu’il a pu répondre à la demande.
Définissez le projet ClientApp comme projet de démarrage (cliquez dessus avec le bouton droit dans le Explorateur de solutions> Set en tant que projet de démarrage) et exécutez la solution. Entrez le numéro 1 dans la zone de texte, puis cliquez sur le bouton. Vous devez obtenir « Chair : Prix = 88,99 » de retour du service.
Si l’appel app service échoue, vérifiez ce qui suit dans le projet ClientApp :
this.inventoryService.PackageFamilyName = "...";
.this.inventoryService.AppServiceName = "com.microsoft.inventory";
.Si vous rencontrez un état AppUnavailable après avoir essayé de vous connecter à un service d’application, vérifiez ce qui suit :
<Extensions>
et ses éléments enfants ont été ajoutés au fichier Package.appxmanifest appartenant au projet du fournisseur d’applications, comme spécifié ci-dessus dans Ajouter une extension app service à Package.appxmanifest.<uap3:AppService Name="..." />
spécifiée dans le fichier Package.appxmanifest du projet package.appxmanifest du projet de fournisseur d’applications.EntryPoint
spécifié dans l’élément <uap:Extension ...>
du fichier Package.appxmanifest de votre projet de fournisseur d’application correspond à l’espace de noms et au nom de classe de la classe publique qui implémente IBackgroundTask dans votre projet App Service.Si le débogueur ne s’arrête pas aux points d’arrêt dans votre fournisseur app service ou vos projets App Service, vérifiez ce qui suit :
Cet exemple fournit une introduction à la création d’un service d’application qui s’exécute en tant que tâche en arrière-plan et l’appelant à partir d’une autre application. Les éléments clés à noter sont les suivants :
windows.appService
au fichier Package.appxmanifest du fournisseur d’app service.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();
}
}
}
}
Entrainement
Parcours d’apprentissage
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Documentation
Convertissez un code de service d’application qui s’exécutait dans un processus distinct en arrière-plan en code qui s’exécute dans le même processus que votre fournisseur de service d’application.
Partager des données - UWP applications
Cet article explique comment prendre en charge le contrat de partage dans une application de bureau ou de plateforme Windows universelle (UWP).
Déclarations des fonctionnalités d’application - UWP applications
Pour accéder à certaines API Windows, certaines ressources (images ou musique) ou certains appareils (appareil photo ou microphone), vous devez déclarer les fonctionnalités de l’application dans le manifeste du package de votre application Windows.
Communication entre les applications - UWP applications
Cette section explique comment partager des données entre des applications UWP, notamment comment utiliser le contrat de partage, copier et coller, et glisser-déplacer.