Udostępnij przez


Napisz dostosowaną wtyczkę dla Portalu Urządzeń Windows

Dowiedz się, jak napisać aplikację platformy UWP korzystającą z portalu urządzeń z systemem Windows (WDP) do hostowania strony internetowej i dostarczania informacji diagnostycznych.

Począwszy od aktualizacji Windows 10 Creators Update (wersja 1703, kompilacja 15063), można użyć Portalu urządzenia do hostowania interfejsów diagnostycznych aplikacji. W tym artykule omówiono trzy elementy potrzebne do utworzenia DevicePortalProvider dla aplikacji — zmiany w manifeście pakietu aplikacji, skonfigurowanie połączenia aplikacji z usługą Device Portal , oraz obsługę żądania przychodzącego.

Tworzenie nowego projektu aplikacji platformy UWP

W programie Microsoft Visual Studio utwórz nowy projekt aplikacji UWP. Przejdź do Plik > Nowy > Projekt i wybierz pozycję Pusta aplikacja (uniwersalna systemu Windows) dla C#, a następnie kliknij przycisk Dalej. W oknie dialogowym Konfigurowanie nowego projektu. Nadaj projektowi nazwę "DevicePortalProvider", a następnie kliknij przycisk Utwórz. Będzie to aplikacja zawierająca usługę App Service. Może być konieczne zaktualizowanie programu Visual Studio lub zainstalowanie najnowszego Windows SDK.

Dodawanie rozszerzenia devicePortalProvider do manifestu pakietu aplikacji

Aby aplikacja działała jako wtyczka portalu urządzeń, musisz dodać kod do pliku package.appxmanifest . Najpierw dodaj następujące definicje przestrzeni nazw w górnej części pliku. Dodaj je również do atrybutu 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">
    ...

Aby zadeklarować, że aplikacja jest dostawcą portalu urządzeń, należy utworzyć usługę aplikacji i nowe rozszerzenie dostawcy portalu urządzeń, które go używa. Dodaj rozszerzenie windows.appService oraz rozszerzenie windows.devicePortalProvider w elemencie Extensions w obszarze Application. Upewnij się, że atrybuty AppServiceName są zgodne w każdym rozszerzeniu. To wskazuje usłudze Portal urządzeń, że tę usługę aplikacji można uruchomić, aby obsłużyć żądania w przestrzeni nazw handlera.

...   
<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>
...

Atrybut HandlerRoute odwołuje się do przestrzeni nazw REST żądanej przez aplikację. Wszystkie żądania HTTP w tej przestrzeni nazw (niejawnie wraz z symbolem wieloznacznym) odebrane przez usługę Portal Urządzenia zostaną wysłane do Twojej aplikacji do obsługi. W takim przypadku każde pomyślnie uwierzytelnione żądanie HTTP na <ip_address>/MyNamespace/api/* zostanie wysłane do Twojej apki. Konflikty między trasami obsługi są rozstrzygane według zasady "wygrywa najdłuższa pasująca trasa": selekcjonowana jest ta trasa, która pasuje do większej liczby żądań. Oznacza to, że żądanie kierowane do "/MyNamespace/api/foo" będzie zgodne z usługodawcą posiadającym trasę "/MyNamespace/api", a nie z takim, który ma trasę "/MyNamespace".

Dla tej funkcji są wymagane dwie nowe funkcje. należy je również dodać do pliku package.appxmanifest.

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

Uwaga / Notatka

Funkcja "devicePortalProvider" jest ograniczona ("rescap"), co oznacza, że przed opublikowaniem aplikacji należy uzyskać wcześniejsze zatwierdzenie Sklepu. Nie uniemożliwia to jednak lokalnego testowania aplikacji przez ładowanie bezpośrednie. Aby uzyskać więcej informacji na temat funkcji ograniczonych, zobacz Deklaracje możliwości aplikacji.

Konfigurowanie zadania w tle i składnika WinRT

Aby ustawić połączenie z Portalem Urządzeń, aplikacja musi podłączyć połączenie usługi aplikacji z instancją Portalu Urządzeń uruchomioną w aplikacji. W tym celu dodaj do aplikacji nowy składnik WinRT z klasą implementjącą klasę 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;
        //...
    }

Upewnij się, że jego nazwa jest zgodna z przestrzenią nazw i nazwą klasy skonfigurowaną przez program AppService EntryPoint ("MySampleProvider.SampleProvider"). Po wysłaniu pierwszego żądania do dostawcy portalu urządzeń portal urządzenia przechowa żądanie, uruchomi zadanie w tle aplikacji, wywoła metodę Run i przekaże IBackgroundTaskInstance. Następnie aplikacja używa jej do skonfigurowania wystąpienia 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;
}

Istnieją dwa zdarzenia, które muszą być obsługiwane przez aplikację w celu ukończenia pętli obsługi żądań: Zamknięte, za każdym razem, gdy usługa Portal urządzeń zostanie zamknięta, i RequestReceived, która udostępnia przychodzące żądania HTTP i zapewnia główne funkcje dostawcy portalu urządzeń.

Obsługa zdarzenia RequestReceived

Zdarzenie RequestReceived zostanie zgłoszone raz dla każdego żądania HTTP wykonanego na określonej trasie obsługi wtyczki. Pętla obsługi żądań dla dostawców Portalu Urządzeń jest podobna do tej w środowisku NodeJS Express: obiekty żądania i odpowiedzi są dostarczane wraz ze zdarzeniem, a procedura obsługująca odpowiada, wypełniając obiekt odpowiedzi. W przypadku dostawców portalu urządzeń zdarzenie RequestReceived i jego procedury obsługi używają obiektów Windows.Web.Http.HttpRequestMessage i 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;            
    }
    //...
}

W tej przykładowej procedurze obsługi żądań najpierw wyciągamy obiekty żądania i odpowiedzi z parametru args , a następnie tworzymy ciąg z adresem URL żądania i dodatkowym formatowaniem HTML. Jest on dodawany do obiektu Response jako wystąpienie HttpStringContent. Dozwolone są również inne klasy IHttpContent , takie jak "String" i "Buffer".

Odpowiedź jest następnie ustawiana jako odpowiedź HTTP i otrzymuje kod stanu 200 (OK). Powinna ona być renderowana zgodnie z oczekiwaniami w przeglądarce, która wykonała oryginalne wywołanie. Należy pamiętać, że gdy program obsługi zdarzeń RequestReceived zwróci się, komunikat odpowiedzi jest automatycznie zwracany do agenta użytkownika: nie jest wymagana żadna dodatkowa metoda wysyłania.

komunikat odpowiedzi portalu urządzenia

Udostępnianie zawartości statycznej

Zawartość statyczna może być obsługiwana bezpośrednio z folderu w pakiecie, co znacznie ułatwia dodawanie interfejsu użytkownika do aplikacji. Najprostszym sposobem obsługi zawartości statycznej jest utworzenie folderu zawartości w projekcie, który może zostać zamapowyny na adres URL.

folder statycznej zawartości portalu urządzenia

Następnie dodaj obsługę tras w procedurze obsługi zdarzeń RequestReceived, która wykrywa trasy zawartości statycznej i odpowiednio przypisuje żądanie.

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");
    }
}

Upewnij się, że wszystkie pliki w folderze zawartości są oznaczone jako "Zawartość" i ustawione na wartość "Kopiuj, jeśli nowsze" lub "Kopiuj zawsze" w menu Właściwości programu Visual Studio. Dzięki temu pliki będą znajdować się w pakiecie AppX podczas wdrażania.

konfigurowanie kopiowania plików zawartości statycznej

Korzystanie z zasobów i interfejsów API istniejącego portalu urządzeń

Zawartość statyczna obsługiwana przez dostawcę portalu urządzenia jest serwowana na tym samym porcie co podstawowa usługa Portalu urządzenia. Oznacza to, że można odwoływać się do istniejących plików JS i CSS, które są dołączone do Portalu urządzenia, używając prostych tagów <link> i <script> w kodzie HTML. Ogólnie rzecz biorąc, sugerujemy użycie rest.js, które opakowują wszystkie podstawowe interfejsy API REST Portalu Urządzeń w wygodny obiekt webbRest oraz pliku common.css, który pozwoli Ci dostosować styl treści do reszty interfejsu użytkownika Portalu Urządzeń. Przykład można zobaczyć na stronie index.html zawartej w przykładzie. Używa rest.js do pobierania nazwy urządzenia i uruchamiania procesów z portalu urządzeń.

dane wyjściowe wtyczki portalu urządzeń

Co ważne, użycie metod HttpPost/DeleteExpect200 w webbRest spowoduje automatyczne wykonywanie obsługi CSRF, co umożliwia twojej stronie internetowej wywoływanie REST API zmieniających stan.

Uwaga / Notatka

Zawartość statyczna dołączona do Portalu Urządzeń nie zawiera gwarancji przed zmianami powodującymi problemy z kompatybilnością. Chociaż interfejsy API nie powinny się często zmieniać, mogą się zmieniać, w szczególności w plikach common.js i controls.js, których dostawca nie powinien używać.

Debugowanie połączenia portalu urządzeń

Aby debugować zadanie w tle, musisz zmienić sposób uruchamiania kodu przez program Visual Studio. Wykonaj poniższe kroki, aby debugować połączenie usługi App Service, aby sprawdzić, jak dostawca obsługuje żądania HTTP:

  1. W menu Debug (Debugowanie) wybierz pozycję DevicePortalProvider Properties (Właściwości elementu DevicePortalProvider).
  2. Na karcie Debugowanie, w sekcji Akcja startowa, wybierz pozycję „Nie uruchamiaj, ale debuguj mój kod, gdy się rozpocznie”.
    umieszczanie wtyczki w trybie debugowania
  3. Ustaw punkt przerwania w funkcji obsługi RequestReceived. punkt przerwania w procedurze obsługi żądań

Uwaga / Notatka

Upewnij się, że architektura kompilowanego systemu jest dokładnie zgodna z architekturą obiektu docelowego. Jeśli używasz 64-bitowego komputera, musisz wdrożyć przy użyciu kompilacji AMD64. 4. Naciśnij F5, aby wdrożyć aplikację 5. Wyłącz aplikację Device Portal, a następnie włącz ją ponownie, aby znalazła aplikację (wymagana tylko w przypadku zmiany manifestu aplikacji — resztę czasu można po prostu ponownie wdrożyć i pominąć ten krok). 6. W przeglądarce uzyskaj dostęp do przestrzeni nazw dostawcy, a punkt przerwania powinien zostać osiągnięty.