Partager via


Écrire un plug-in personnalisé pour le Portail d’appareil Windows

Découvrez comment écrire une application UWP qui utilise le portail d’appareil Windows (WDP) pour héberger une page web et fournir des informations de diagnostic.

À compter de Windows 10 Creators Update (version 1703, build 15063), vous pouvez utiliser Device Portal pour héberger les interfaces de diagnostic de votre application. Cet article décrit les trois éléments nécessaires pour créer un DevicePortalProvider pour votre application : le manifeste de package d’application modifications, la configuration de la connexion de votre application au service Device Portalet la gestion d’une demande entrante.

Créer un projet d’application UWP

Dans Microsoft Visual Studio, créez un projet d’application UWP. Accédez à Fichier > Nouveau > Projet et sélectionnez Application vide (Windows Universelle) pour C#, puis cliquez sur Suivant. Dans la boîte de dialogue Configuration de votre nouveau projet. Nommez le projet « DevicePortalProvider », puis cliquez sur Créer. Il s’agit de l’application qui contient le service d’application. Vous devrez peut-être mettre à jour Visual Studio ou installer la dernière sdk Windows.

Ajouter l’extension devicePortalProvider au manifeste de votre package d’application

Vous devez ajouter du code à votre fichier package.appxmanifest afin de rendre votre application fonctionnelle en tant que plug-in Device Portal. Tout d’abord, ajoutez les définitions d’espace de noms suivantes en haut du fichier. Ajoutez-les également à l’attribut IgnorableNamespaces.

<Package
    ... 
    xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
    xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
    IgnorableNamespaces="uap mp rescap uap4">
    ...

Pour déclarer que votre application est un fournisseur de portail d’appareils, vous devez créer un service d’application et une nouvelle extension de fournisseur de portail d’appareil qui l’utilise. Ajoutez l’extension windows.appService et l’extension windows.devicePortalProvider dans l’élément Extensions sous Application. Vérifiez que les attributs AppServiceName correspondent dans chaque extension. Cela indique au service Device Portal que ce service d’application peut être lancé pour gérer les requêtes sur l’espace de noms du gestionnaire.

...   
<Application 
    Id="App" 
    Executable="$targetnametoken$.exe"
    EntryPoint="DevicePortalProvider.App">
    ...
    <Extensions>
        <uap:Extension Category="windows.appService" EntryPoint="MySampleProvider.SampleProvider">
            <uap:AppService Name="com.sampleProvider.wdp" />
        </uap:Extension>
        <uap4:Extension Category="windows.devicePortalProvider">
            <uap4:DevicePortalProvider 
                DisplayName="My Device Portal Provider Sample App" 
                AppServiceName="com.sampleProvider.wdp" 
                HandlerRoute="/MyNamespace/api/" />
        </uap4:Extension>
    </Extensions>
</Application>
...

L’attribut HandlerRoute fait référence à l’espace de noms REST revendiqué par votre application. Toutes les requêtes HTTP sur cet espace de noms (implicitement suivis d’un caractère générique) reçues par le service Device Portal sont envoyées à votre application pour être gérées. Dans ce cas, toute requête HTTP authentifiée correctement à <ip_address>/MyNamespace/api/* sera envoyée à votre application. Les conflits entre les itinéraires de gestionnaire sont réglés par une vérification « plus longue gagne » : l'itinéraire qui correspond à un plus grand nombre de requêtes est sélectionné, ce qui signifie qu'une requête adressée à « /MyNamespace/api/foo » sera associée à un fournisseur ayant « /MyNamespace/api » plutôt qu'à un ayant « /MyNamespace ».

Deux nouvelles fonctionnalités sont requises pour cette fonctionnalité. ils doivent également être ajoutés à votre fichier package.appxmanifest.

...
<Capabilities>
    ...
    <Capability Name="privateNetworkClientServer" />
    <rescap:Capability Name="devicePortalProvider" />
</Capabilities>
...

Remarque

La fonctionnalité « devicePortalProvider » est restreinte (« récapitulatif »), ce qui signifie que vous devez obtenir une approbation préalable du Store avant que votre application puisse être publiée. Toutefois, cela ne vous empêche pas de tester votre application localement avec le sideloading. Pour plus d’informations sur les fonctionnalités restreintes, consultez déclarations de fonctionnalités d’application.

Configurer votre tâche en arrière-plan et le composant WinRT

Pour configurer la connexion Device Portal, votre application doit connecter une connexion app service à partir du service Device Portal avec l’instance de Device Portal s’exécutant dans votre application. Pour ce faire, ajoutez un nouveau composant WinRT à votre application avec une classe qui implémente IBackgroundTask.

using Windows.System.Diagnostics.DevicePortal;
using Windows.ApplicationModel.Background;

namespace MySampleProvider {
    // Implementing a DevicePortalConnection in a background task
    public sealed class SampleProvider : IBackgroundTask {
        BackgroundTaskDeferral taskDeferral;
        DevicePortalConnection devicePortalConnection;
        //...
    }

Assurez-vous que son nom correspond à l’espace de noms et au nom de classe configurés par le point d’entrée AppService (« MySampleProvider.SampleProvider »). Lorsque vous effectuez votre première requête auprès de votre fournisseur Device Portal, Device Portal stockera la requête, lancera la tâche en arrière-plan de votre application, appellera sa méthode Run et passera une IBackgroundTaskInstance. Votre application l’utilise ensuite pour configurer une instance DevicePortalConnection.

// Implement background task handler with a DevicePortalConnection
public void Run(IBackgroundTaskInstance taskInstance) {
    // Take a deferral to allow the background task to continue executing 
    this.taskDeferral = taskInstance.GetDeferral();
    taskInstance.Canceled += TaskInstance_Canceled;

    // Create a DevicePortal client from an AppServiceConnection 
    var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    var appServiceConnection = details.AppServiceConnection;
    this.devicePortalConnection = DevicePortalConnection.GetForAppServiceConnection(appServiceConnection);

    // Add Closed, RequestReceived handlers 
    devicePortalConnection.Closed += DevicePortalConnection_Closed;
    devicePortalConnection.RequestReceived += DevicePortalConnection_RequestReceived;
}

Il existe deux événements qui doivent être gérés par l’application pour terminer la boucle de gestion des demandes : fermé, pour chaque fois que le service Device Portal s’arrête, et RequestReceived, qui expose les requêtes HTTP entrantes et fournit les principales fonctionnalités du fournisseur Device Portal.

Gérer l’événement RequestReceived

L’événement RequestReceived sera déclenché une fois pour chaque requête HTTP effectuée sur l’itinéraire de gestionnaire spécifié de votre plug-in. La boucle de gestion des demandes pour les fournisseurs Device Portal est similaire à celle de NodeJS Express : les objets de requête et de réponse sont fournis avec l’événement, et le gestionnaire répond en remplissant l’objet de réponse. Dans les fournisseurs Device Portal, l’événement RequestReceived et ses gestionnaires utilisent les objets Windows.Web.Http.HttpRequestMessage et HttpResponseMessage.

// Sample RequestReceived echo handler: respond with an HTML page including the query and some additional process information. 
private void DevicePortalConnection_RequestReceived(DevicePortalConnection sender, DevicePortalConnectionRequestReceivedEventArgs args)
{
    var req = args.RequestMessage;
    var res = args.ResponseMessage;

    if (req.RequestUri.AbsolutePath.EndsWith("/echo"))
    {
        // construct an html response message
        string con = "<h1>" + req.RequestUri.AbsoluteUri + "</h1><br/>";
        var proc = Windows.System.Diagnostics.ProcessDiagnosticInfo.GetForCurrentProcess();
        con += String.Format("This process is consuming {0} bytes (Working Set)<br/>", proc.MemoryUsage.GetReport().WorkingSetSizeInBytes);
        con += String.Format("The process PID is {0}<br/>", proc.ProcessId);
        con += String.Format("The executable filename is {0}", proc.ExecutableFileName);
        res.Content = new Windows.Web.HttpStringContent(con);
        res.Content.Headers.ContentType = new Windows.Web.Http.Headers.HttpMediaTypeHeaderValue("text/html");
        res.StatusCode = Windows.Web.Http.HttpStatusCode.Ok;            
    }
    //...
}

Dans cet exemple de gestionnaire de requêtes, nous extrayons d’abord les objets de requête et de réponse à partir des arguments paramètre, puis créons une chaîne avec l’URL de la requête et une mise en forme HTML supplémentaire. Cela est ajouté à l’objet Response en tant qu’instance HttpStringContent. D’autres classes IHttpContent, telles que celles pour « String » et « Buffer », sont également autorisées.

La réponse est ensuite définie comme une réponse HTTP et reçoit un code d'état 200 (OK). Il doit s’afficher comme prévu dans le navigateur qui a effectué l’appel d’origine. Notez que lorsque le gestionnaire d’événements RequestReceived retourne, le message de réponse est automatiquement retourné à l’agent utilisateur : aucune méthode « send » supplémentaire n’est nécessaire.

message de réponse du portail de l'appareil

Fourniture de contenu statique

Le contenu statique peut être servi directement à partir d’un dossier au sein de votre package, ce qui facilite l’ajout d’une interface utilisateur à votre fournisseur. Le moyen le plus simple de servir du contenu statique consiste à créer un dossier de contenu dans votre projet pouvant être mappé à une URL.

dossier de contenu statique du portail de l'appareil

Ensuite, ajoutez un gestionnaire de routage dans votre RequestReceived gestionnaire d’événements qui détecte les itinéraires de contenu statique et mappe correctement une requête.

if (req.RequestUri.LocalPath.ToLower().Contains("/www/")) {
    var filePath = req.RequestUri.AbsolutePath.Replace('/', '\\').ToLower();
    filePath = filePath.Replace("\\backgroundprovider", "")
    try {
        var fileStream = Windows.ApplicationModel.Package.Current.InstalledLocation.OpenStreamForReadAsync(filePath).GetAwaiter().GetResult();
        res.StatusCode = HttpStatusCode.Ok;
        res.Content = new HttpStreamContent(fileStream.AsInputStream());
        res.Content.Headers.ContentType = new HttpMediaTypeHeaderValue("text/html");
    } catch(FileNotFoundException e) {
        string con = String.Format("<h1>{0} - not found</h1>\r\n", filePath);
        con += "Exception: " + e.ToString();
        res.Content = new Windows.Web.Http.HttpStringContent(con);
        res.StatusCode = Windows.Web.Http.HttpStatusCode.NotFound;
        res.Content.Headers.ContentType = new Windows.Web.Http.Headers.HttpMediaTypeHeaderValue("text/html");
    }
}

Vérifiez que tous les fichiers à l’intérieur du dossier de contenu sont marqués comme « Contenu » et définissez sur « Copier si plus récent » ou « Copier toujours » dans le menu Propriétés de Visual Studio. Cela garantit que les fichiers se trouvent à l’intérieur de votre package AppX lorsque vous le déployez.

configurer la copie de fichiers de contenu statiques

Utilisation de ressources et d’API Device Portal existantes

Le contenu statique servi par un fournisseur Device Portal est servi sur le même port que le service Principal Device Portal. Cela signifie que vous pouvez référencer les fichiers JS et CSS existants inclus dans Device Portal avec des balises de <link> et de <script> simples dans votre code HTML. En général, nous vous suggérons d’utiliser rest.js, qui encapsule toutes les API REST du portail d’appareil principaux dans un objet webbRest pratique et le fichier common.css, qui vous permettra de mettre en forme votre contenu pour s’adapter au reste de l’interface utilisateur du portail d’appareil. Vous pouvez voir un exemple de ceci dans la page index.html incluse dans l’exemple. Il utilise rest.js pour récupérer le nom de l’appareil et les processus en cours d’exécution à partir du portail d’appareil.

sortie du module du portail de l’appareil

Il est important de noter que l’utilisation des méthodes HttpPost/DeleteExpect200 sur webbRest effectue automatiquement la gestion CSRF pour vous, ce qui permet à votre page web d’appeler des API REST à changement d’état.

Remarque

Le contenu statique inclus dans Device Portal n’est pas fourni avec une garantie contre les changements non compatibles. Bien que les API ne soient pas censées changer souvent, elles peuvent, en particulier dans les fichiers common.js et controls.js, que votre fournisseur ne doit pas utiliser.

Débogage de la connexion du Portail de périphériques

Pour déboguer votre tâche en arrière-plan, vous devez modifier la façon dont Visual Studio exécute votre code. Suivez les étapes ci-dessous pour déboguer une connexion App Service pour inspecter la façon dont votre fournisseur gère les requêtes HTTP :

  1. Dans le menu Débogage, sélectionnez les propriétés de DevicePortalProvider.
  2. Sous l’onglet Débogage, dans la section Action de démarrage, sélectionnez « Ne pas lancer, mais déboguer mon code au démarrage ».
    placer le plug-in en mode débogage
  3. Définissez un point d’arrêt dans votre fonction de gestionnaire RequestReceived. point d’arrêt au gestionnaire de requêteReçue

Remarque

Vérifiez que l’architecture de build correspond exactement à l’architecture de la cible. Si vous utilisez un PC 64 bits, vous devez déployer à l’aide d’une build AMD64. 4. Appuyez sur F5 pour déployer votre application 5. Désactivez Device Portal, puis réactivez-le pour qu’il trouve votre application (nécessaire uniquement lorsque vous modifiez votre manifeste d’application, le reste du temps, vous pouvez simplement le redéployer et ignorer cette étape). 6. Dans votre navigateur, accédez à l’espace de noms du fournisseur, et le point d’arrêt devrait être atteint.