Juni 2019

Band 34, Nummer 6

[DevOps]

MSIX: Der moderne Weg zur Bereitstellung von Desktop-Apps unter Windows

Von Magnus Montin | Juni 2019 | Code abrufen

MSIX ist das neue Paketformat, das mit dem Update von Windows 10 aus Oktober 2018 eingeführt wurde. Es zielt darauf ab, die besten aller bisherigen Installationstechnologien wie MSI und ClickOnce zusammenzuführen und wird die empfohlene Methode für die zukünftige Installation von Anwendungen unter Windows sein. Dieser Artikel zeigt Ihnen, wie Sie die Paketerstellung einer .NET-Desktopanwendung ausführen und wie Sie Continuous Integration (CI), Continuous Deployment (CD) und automatische Updates von quergeladenen MSIX-Paketen mithilfe von Azure Pipelines einrichten.

Zunächst einige Hintergrundinformationen. In Windows 8 hat Microsoft eine API und Runtime namens Windows-Runtime eingeführt, die hauptsächlich darauf abzielte, einer neuen Art von Anwendung, die ursprünglich als „moderne“ App, „Metro“-App, „immersive“-App oder einfach nur als „Windows Store“-App bezeichnet wurde, eine Reihe von Plattformdiensten zur Verfügung zu stellen. Diese Art von App wurde aufgrund der Revolution der mobilen Geräte entwickelt und zielte typischerweise auf mehrere Geräteformfaktoren wie Smartphones, Tablets und Laptops ab. Sie wurde in der Regel über den zentralen Microsoft Store installiert und aktualisiert.

Diese Klasse von Apps hat sich seitdem stark weiterentwickelt und ist heute als UWP-App (universelle Windows-Plattform) bekannt. UWP-Apps werden in einer Sandbox namens „AppContainer“ ausgeführt, die von anderen Prozessen isoliert ist. Sie deklarieren explizit Funktionen, die die für eine ordnungsgemäße Funktion benötigten Berechtigungen erfordern, und es liegt am Benutzer zu entscheiden, ob diese Funktionen akzeptiert werden sollen. Dies steht im Gegensatz zu einer herkömmlichen Desktopanwendung, die in der Regel als voll vertrauenswürdiger Prozess mit den vollständigen Lese- und Schreibberechtigungen des aktuellen Benutzers ausgeführt wird.

Im Anniversary Update von Windows 10 hat Microsoft die Desktop-Brücke (auch bekannt als Centennial-Projekt) eingeführt. Mit ihr konnten Sie Ihre traditionelle Desktopanwendung als UWP-App-Paket erstellen, aber dennoch als voll vertrauenswürdigen Prozess ausführen. Ein Anwendungspaket kann in den Microsoft Store oder den Store for Business hochgeladen werden und profitiert von der optimierten Bereitstellung und den integrierten Lizenzfunktionen sowie den Funktionen für automatische Updates des Stores. Nachdem Sie Ihre Anwendung als Paket erstellt haben, können Sie auch mit der Verwendung der neuen Windows 10-APIs beginnen und Ihren Code zur UWP migrieren, um Kunden auf allen Geräten zu erreichen.

Auch wenn Sie sich nicht für den Store oder die UWP interessieren, können Sie Ihre Branchendesktopanwendungen dennoch als Paket bereitstellen, um die Vorteile des neuen App-Modells von Windows 10 zu nutzen. Es bietet saubere Installationen und Deinstallationen von Apps, indem es automatisch alle Vorgänge in der Registrierung und einigen bekannten Systemordnern in einen lokalen Ordner der installierten Anwendung umleitet, in dem ein virtuelles Dateisystem und eine Registrierung eingerichtet werden. Dazu müssen Sie in Ihrem Quellcode keine Vorkehrungen treffen – dies wird von Windows automatisch für Sie erledigt. Die Idee dabei ist, dass bei der Deinstallation eines Pakets der gesamte lokale Ordner entfernt wird, ohne Spuren der App auf dem System zu hinterlassen.

MSIX ist im Grunde genommen ein Nachfolger der Desktop-Brücke, und der Inhalt eines MSIX-Pakets (und die Einschränkungen, die für Anwendungspakete gelten) sind ungefähr die gleichen wie beim APPX-Format, das die Desktop-Brücke verwendet. Die Anforderungen finden Sie in der offiziellen Dokumentation unter bit.ly/2OvCcVW. Diese sollten beachtet werden, bevor Sie sich dafür entscheiden, Anwendungspakete zu erstellen. Einige davon gelten nur für Apps, die im Store veröffentlicht werden.

MSIX fügt ein neues Feature namens Änderungspakete hinzu. Es handelt sich um ein Konzept ähnlich wie bei MST-Transformationen, das es IT-Administratoren ermöglicht, eine App (in der Regel von einem Drittanbieter) anzupassen, ohne sie bei jedem Release eines neuen Features oder Bugfixes von Grund auf neu verpacken zu müssen. Das Änderungspaket wird zur Laufzeit mit der Hauptanwendung gemergt und kann einige Funktionen der Anwendung deaktivieren, z.B. durch Ändern einiger Registrierungseinstellungen. Aus Entwicklersicht bedeutet dies vielleicht keinen allzu großen Nutzen, wenn Sie Besitzer sowohl des Quellcodes als auch der Build- und-Releasepipelines für Ihre Apps sind, aber für große Unternehmen kann es Kosten senken und eine so genannte „Package Paralysis“ (Paketlähmung) verhindern.

Die Definition des MSIX-Formats ist Open-Source auf GitHub, und Microsoft plant, ein SDK bereitzustellen, mit dem MSIX-Pakete unter allen wichtigen Betriebssystemen (einschließlich Linux und macOS) verpackt und entpackt werden können. MSIX wurde im Oktober 2018 offiziell mit Version 1809 von Windows 10 eingeführt, und Microsoft hat dann Unterstützung für ältere Versionen – das Update aus April 2018 (Version 1803) und das Fall Creators Update aus Oktober 2017 (Version 1709) – hinzugefügt.

Paketerstellung

Wenn Sie über ein vorhandenes Installationsprogramm verfügen, steht im Store ein MSIX-Paketerstellungstool zur Verfügung, mit dem Sie die Konvertierung in das MSIX-Format ausführen können. Auf diese Weise können Administratoren vorhandene Anwendungen verpacken, ohne überhaupt Zugriff auf den ursprünglichen Quellcode zu besitzen. Für Entwickler bietet Visual Studio 2017 ab Version 15.5 ein Windows-Anwendungspaket-Erstellungsprojekt, das den Prozess der Paketerstellung einer vorhandenen Anwendung einfach macht. Sie finden es unter „Datei > Hinzufügen > Neues Projekt > Installiert > Visual C# > Windows universell“. Es enthält einen Ordner „Application“, auf den Sie im Projektmappen-Explorer mit der rechten Maustaste klicken können. Anschließend können Sie einen Verweis auf Ihre WPF- (Windows Presentation Foundation), WinForms- (Windows Forms) oder beliebige andere Desktopprojekte hinzufügen, die Sie verpacken möchten. Wenn Sie dann mit der rechten Maustaste auf die referenzierte Anwendung klicken und „Als Einstiegspunkt festlegen“ auswählen, können Sie Ihre Anwendung genau so erstellen, ausführen und debuggen, wie Sie es gewohnt sind.

Der Unterschied zwischen dem Starten des ursprünglichen Desktopprozesses und dem Verpackungsprojekt besteht darin, dass letzteres Ihre Anwendung in einem modernen App-Container ausführt. Hinter den Kulissen verwendet Visual Studio die Befehlszeilentools MakeAppx und SignTool aus dem Windows SDK, um zunächst eine MSIX-Datei zu erstellen und sie dann mit einem Zertifikat zu signieren. Dieser Schritt ist nicht optional. Alle MSIX-Pakete müssen mit einem Zertifikat signiert werden, das mit einer vertrauenswürdigen Stammzertifizierungsstelle auf dem Computer verkettet ist, auf dem Sie die verpackte Anwendung installieren und ausführen möchten.

Digitale Signatur: Das Verpackungsprojekt enthält eine standardmäßige, kennwortgeschützte Datei im PFX-Format (Personal Information Exchange), die Sie wahrscheinlich durch Ihre eigene Datei ersetzen möchten. Wenn Ihr Unternehmen Ihnen kein Codesignaturzertifikat zur Verfügung stellt, können Sie entweder eines bei einer vertrauenswürdigen Zertifizierungsstelle erwerben oder ein selbstsigniertes Zertifikat erstellen. Es gibt eine Option „Testzertifikat erstellen“ und einen Import-Assistenten in Visual Studio. Öffnen Sie die Datei „Package.appxmanifest“ im standardmäßigen Anwendungsmanifest-Designer, und suchen Sie unter der Registerkarte „Verpackung“. Wenn Sie nicht so gern mit Assistenten und Dialogfeldern arbeiten, können Sie das PowerShell-Cmdlet New-SelfSignedCertificate verwenden, um ein Zertifikat zu erstellen:

> New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=MyCompany,
  O=MyCompany, L=Stockholm, S=N/A, C=Sweden" -KeyUsage DigitalSignature
    -FriendlyName MyCertificate -CertStoreLocation "Cert:\LocalMachine\My"
      -TextExtension @('2.5.29.37={text}1.3.6.1.5.5.7.3.3',
        '2.5.29.19={text}Subject Type:End Entity')

Das Cmdlet gibt einen Fingerabdruck (wie hier A27...D9F) aus, den Sie an ein anderes Cmdlet (Move-Item) übergeben können, um das Zertifikat in den vertrauenswürdigen Stammzertifizierungsspeicher zu verschieben:

>Move-Item Cert:\LocalMachine\My\A27A5DBF5C874016E1A0DEBF38A97061F6625D9F
  -Destination Cert:\LocalMachine\Root

Auch hier müssen Sie das Zertifikat auf allen Computern, auf denen Sie die verpackte Anwendung installieren und ausführen möchten, in diesem Speicher installieren. Außerdem müssen Sie das Querladen von Apps auf diesen Geräten aktivieren. Auf einem nicht verwalteten Computer kann dies unter „Update und Sicherheit > Für Entwickler“ in der Einstellungen-App erfolgen. Auf einem Gerät, das von einer Organisation verwaltet wird, können Sie Querladen aktivieren, indem Sie eine Richtlinie mit einem Anbieter für mobile Geräteverwaltung (MDM) durchsetzen.

Der Fingerabdruck kann auch verwendet werden, um das Zertifikat mit dem Cmdlet Export-PfxCertificate in eine neue PFX-Datei zu exportieren:

>$pwd = ConvertTo-SecureString -String secret -Force -AsPlainText
>Export-PfxCertificate -cert
  "Cert:\LocalMachine\Root\A27A5DBF5C874016E1A0DEBF38A97061F6625D9F"
    -FilePath "c:/<SolutionFolder>/Msix/certificate.pfx" -Password $pwd

Denken Sie daran, Visual Studio anzuweisen, die generierte PFX-Datei zu verwenden, um das MSIX-Paket zu signieren, indem Sie sie auf der Registerkarte „Verpackung“ im Designer auswählen, oder indem Sie die WAPPROJ-Projektdatei manuell bearbeiten und die Werte der Elemente <PackageCertificateKeyFile> und <PackageCertificateThumbprint> ersetzen.

Paketmanifest: Die Datei „Package.appxmanifest“ ist eine XML-basierte Vorlage, mit der der Buildprozess eine digital signierte Datei „AppxManifest.xml“ generiert, die alle Informationen enthält, die das Betriebssystem zum Bereitstellen, Anzeigen und Aktualisieren der verpackten App benötigt. Hier geben Sie den Anzeigenamen und das Logo Ihrer App an, wie es nach der Installation der App in der Windows-Shell angezeigt wird.

Stellen Sie sicher, dass die Subject-Eigenschaft des Zertifikats, mit dem Sie das MSIX-Paket signieren, genau dem Wert des Publisher-Attributs des Identity-Elements entspricht. Da eine verpackte Desktopanwendung nur auf Desktopgeräten ausgeführt werden kann, sollten Sie auch das TargetDeviceFamily-Element mit dem Namen Windows.Universal aus dem Dependencies-Element in der von Visual Studio generierten Standardvorlage entfernen.

Die MinVersion- und MaxVersionTested-Attribute (oder „Mindestversion“ und „Zielversion“, wie sie im Dialogfeld genannt werden, das beim Erstellen eines Paketerstellungsprojekts angezeigt wird) sind ein UWP-Konzept, bei dem das erstgenannte Attribut die älteste Version des Betriebssystems angibt, mit dem Ihre Anwendung kompatibel ist, und das letztgenannte verwendet wird, um den Satz von APIs zu identifizieren, die beim Kompilieren der Anwendung verfügbar sind. Beim Verpacken von Desktopanwendungen, die keine Windows 10-APIs aufrufen, sollten Sie die gleiche Version auswählen. Wenn Sie dies nicht tun, sollte Ihr Code API-Laufzeitüberprüfungen enthalten, um Ausnahmen zu vermeiden, wenn Sie Ihre App auf Geräten ausführen, die für die Mindestversion konzipiert sind.

Zum Generieren des eigentlichen MSIX-Pakets steht unter „Projekt > Store > App-Pakete erstellen“ in Visual Studio ein Assistent zur Verfügung. Ein Endbenutzer installiert ein MSIX-Paket durch einfaches Doppelklicken auf die generierte MSIX-Datei. Dadurch wird ein integriertes, nicht anpassbares Dialogfeld angezeigt (siehe Abbildung1), das Sie schrittweise durch den Vorgang der Installation der App führt.

Der App-Installer und die MSIX-Installationsbenutzeroberfläche unter Windows 10
Abbildung 1: Der App-Installer und die MSIX-Installationsbenutzeroberfläche unter Windows 10

Continuous Integration

Wenn Sie für Ihre MSIX-Pakete CI einrichten möchten, bietet Azure Pipelines umfassende Unterstützung. Pipelines unterstützt CAC (Configuration as Code) durch die Verwendung von YAML-Dateien und bietet einen in der Cloud gehosteten Build-Agent, der die gesamte Software enthält, die zur Erstellung von vorinstallierten MSIX-Paketen benötigt wird.

Vor dem Erstellen des Paketerstellungsprojekts über die MSBuild-Befehlszeile (auf die gleiche Weise wie mit dem Assistenten in Visual Studio) kann der Buildprozess das MSIX-Paket mit einer Versionsangabe versehen, die durch Bearbeiten des Version-Attributs des Package-Elements in der Datei „Package.appxmanifest“ generiert wird. In Azure Pipelines kann dies erreicht werden, indem ein Ausdruck zum Festlegen einer Zählervariablen verwendet wird, die für jeden Build erhöht wird, sowie durch ein PowerShell-Skript, das die Klasse System.Xml.Linq.XDocument in .NET verwendet, um den Wert des Attributs zu ändern. Abbildung 2 zeigt eine YAML-Beispieldatei, die ein MSIX-Paket basierend auf einem Paketerstellungsprojekt mit einer Versionsangabe versieht und erstellt, bevor es in ein Stagingverzeichnis auf dem Build-Agent kopiert wird.

Abbildung 2: Die YAML-Datei, die die MSIX-Buildpipeline definiert

pool: 
  vmImage: vs2017-win2016
variables:
  buildPlatform: 'x86'
  buildConfiguration: 'release'
  major: 1
  minor: 0
  build: 0
  revision: $[counter('rev', 0)]
steps:
- powershell: |
   [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
   $path = "Msix/Package.appxmanifest"
   $doc = [System.Xml.Linq.XDocument]::Load($path)
   $xName =
     [System.Xml.Linq.XName]
       "{http://schemas.microsoft.com/appx/manifest/foundation/windows10}Identity"
   $doc.Root.Element($xName).Attribute("Version").Value =
     "$(major).$(minor).$(build).$(revision)";
   $doc.Save($path)
  displayName: 'Version Package Manifest'
- task: MSBuild@1
  inputs:
    solution: Msix/Msix.wapproj
    platform: $(buildPlatform)
    configuration: $(buildConfiguration)
    msbuildArguments: '/p:OutputPath=NonPackagedApp
     /p:UapAppxPackageBuildMode=SideLoadOnly  /p:AppxBundle=Never /p:AppxPackageOutput=$(Build.ArtifactStagingDirectory)\MsixDesktopApp.msix /p:AppxPackageSigningEnabled=false'
  displayName: 'Package the App'
- task: DownloadSecureFile@1
  inputs:
    secureFile: 'certificate.pfx'
  displayName: 'Download Secure PFX File'
- script: '"C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\signtool"
    sign /fd SHA256 /f $(Agent.TempDirectory)/certificate.pfx /p secret $(
    Build.ArtifactStagingDirectory)/MsixDesktopApp.msix'
  displayName: 'Sign MSIX Package'
- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: drop'

Der Name des gehosteten virtuellen Computers, der Visual Studio 2017 unter Windows Server 2016 ausführt, lautet vs2017-win2016. Auf ihm sind die erforderlichen UWP- und .NET-Entwicklungsworkloads einschließlich SignTool installiert, das verwendet wird, um das MSIX-Paket zu signieren, nachdem es von MSBuild erstellt wurde. Beachten Sie, dass die PFX-Datei nicht der Quellcodeverwaltung hinzugefügt werden sollte. Sie wird auch von Git standardmäßig ignoriert. Stattdessen sollte sie als geheime Datei auf der Registerkarte „Bibliothek“ im Webportal in Azure Pipelines hochgeladen werden. Da sie den privaten Schlüssel des Zertifikats enthält, der die digitale Signatur und die Identität Ihres Unternehmens darstellt, möchten Sie sie nicht an mehr Personen als erforderlich verteilen.

In großen Unternehmen, in denen Sie Ihre Software in verschiedenen Phasen in mehreren Umgebungen freigeben, gilt es als eine bewährte Methode, die Pakete im Rahmen des Releaseprozesses zu signieren und die Buildpipeline unsignierte Pakete generieren zu lassen. Auf diese Weise können Sie nicht nur verschiedene Zertifikate zum Signieren für verschiedene Umgebungen verwenden, sondern auch Ihre Pakete in den Store hochladen, in dem sie durch ein Microsoft-Zertifikat signiert werden.

Beachten Sie auch, dass Geheimnisse (beispielsweise das Kennwort für die PFX-Datei) nicht in der YAML-Datei enthalten sein sollten. Im Gegensatz zu Variablen, die die Zielprozessorarchitektur und die Paketversion angeben, werden sie in der Webschnittstelle definiert und festgelegt.

Abbildung 3 zeigt den Projektmappen-Explorer für eine WPF-Anwendung, die mit der Standardprojektvorlage in Visual Studio erstellt und mit einem Windows-Anwendungspaket-Erstellungsprojekt verpackt wurde. Die YAML-Datei wurde dem Paketerstellungsprojekt hinzugefügt und wird zusammen mit dem Rest des Codes in ein Quellcoderepository eingecheckt.

Eine verpackte WPF-Anwendung, die bereit ist, in die Quellcodeverwaltung gepusht zu werden
Abbildung 3A: Eine verpackte WPF-Anwendung, die bereit ist, in die Quellcodeverwaltung gepusht zu werden

Um die eigentliche Buildpipeline einzurichten, navigieren Sie zum Azure DevOps-Portal unter dev.azure.com/<organization> und erstellen ein neues Projekt. Wenn Sie noch kein Konto besitzen, können Sie kostenlos ein Konto erstellen. Nachdem Sie sich angemeldet und ein Projekt erstellt haben, können Sie entweder den Quellcode in das für Sie eingerichtete Git-Repository unter https://<organization>@dev.azure.com/\<organization>/<project>/<git/<project>/_git/<project> pushen oder einen anderen Anbieter wie GitHub verwenden. Sie können den Speicherort Ihres Repositorys auswählen, wenn Sie eine neue Pipeline im Portal erstellen, indem Sie zuerst auf die Schaltfläche „Pipelines“ und dann auf „Neue Pipeline“ klicken.

Auf dem folgenden Bildschirm „Konfigurieren“ sollten Sie die Option „Vorhandene Azure Pipelines-YAML-Datei“ und den Pfad zur eingecheckten YAML-Datei in Ihrem Repository auswählen, wie in Abbildung 4 gezeigt.

Die Pipelinekonfigurations-Webbenutzeroberfläche
Abbildung 4: Die Pipelinekonfigurations-Webbenutzeroberfläche

Das MSIX-Paket, das durch den Build generiert wird, kann heruntergeladen und mit einem Doppelklick auf einem beliebigen mit Windows 10 kompatiblem Computer mit installiertem Zertifikat installiert werden, oder Sie können eine CD-Pipeline einrichten, die das Paket auf eine Website oder in eine Dateifreigabe kopiert, von der Ihre Endbenutzer es herunterladen können. Ich werde darauf gleich noch zurückkommen.

Automatische Updates: Während ein MSIX-Paket in der Lage ist, sich selbst zu extrahieren und automatisch jede ältere Version der verpackten Anwendung zu ersetzen, die bei der Installation auf dem Computer vorhanden sein könnte, bietet das MSIX-Format keine integrierte Unterstützung für die automatische Aktualisierung einer bereits installierten App aus einer MSIX-Datei, wenn Sie sie öffnen.

Ab dem Update von Windows 10 aus April 2018 wird jedoch eine App-Installationsdatei unterstützt, die Sie zusammen mit Ihrem Paket bereitstellen können, um automatische Updates zu ermöglichen. Sie enthält ein MainPackage-Element, dessen Uri-Attribut auf das ursprüngliche oder ein aktualisiertes MSIX Paket verweist. Abbildung 5 zeigt ein Beispiel für eine minimale APPINSTALLER-Datei. Beachten Sie, dass das Uri-Attribut des root-Elements eine URL oder einen UNC-Pfad zu einer Dateifreigabe angibt, in der das Betriebssystem nach den aktualisierten Dateien sucht. Wenn sich die URI zwischen einer aktuell installierten Version und einer neuen App-Installationsdatei unterscheidet, wird der Bereitstellungsvorgang an den „alten“ URI weitergeleitet.

Abbildung 5: Eine APPINSTALLER-Datei, die unter \\server\foo nach aktualisierten Dateien sucht

<?xml version="1.0" encoding="utf-8"?>
<AppInstaller xmlns="http://schemas.microsoft.com/appx/appinstaller/2018"
              Version="1.0.0.0"
              Uri="\\server\foo\MsixDesktopApp.appinstaller">
  <MainPackage Name="MyCompany.MySampleApp"
               Publisher="CN=MyCompany, O=MyCompany, L=Stockholm, S=N/A, C=Sweden"
               Version="1.0.0.0"
               Uri="\\server\foo\MsixDesktopApp.msix"
               ProcessorArchitecture="x86"/>
  <UpdateSettings>
    <OnLaunch HoursBetweenUpdateChecks="0" />
  </UpdateSettings>
</AppInstaller>

Das UpdateSettings-Element wird verwendet, um dem System mitzuteilen, wann es nach Updates suchen und ob es den Benutzer zur Aktualisierung zwingen soll. Der vollständige Schemaverweis (einschließlich der unterstützten Namespaces für jede Version von Windows 10) finden Sie in der Dokumentation unter bit.ly/2TGWnCR.

Wenn Sie die APPINSTALLER-Datei in Abbildung 5 zum Paketerstellungsprojekt hinzufügen und die Package Action-Eigenschaft auf „Content“ und die Copy to Output Directory-Eigenschaft auf „Copy if newer“ festlegen, können Sie der YAML-Datei einen weiteren PowerShell-Task hinzufügen, der die Versionsattribute der root- und MainPackage-Elemente aktualisiert und die aktualisierte Datei im Stagingverzeichnis speichert:

- powershell: |
  [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
  $doc = [System.Xml.Linq.XDocument]::Load(
    "$(Build.SourcesDirectory)/Msix/Package.appinstaller")
  $version = "$(major).$(minor).$(build).$(revision)"
  $doc.Root.Attribute("Version").Value = $version;
  $xName =
    [System.Xml.Linq.XName]
      "{http://schemas.microsoft.com/appx/appinstaller/2018}MainPackage"
  $doc.Root.Element($xName).Attribute("Version").Value = $version;
  $doc.Save("$(Build.ArtifactStagingDirectory)/MsixDesktopApp.appinstaller")
displayName: 'Version App Installer File'

In diesem Fall verteilen Sie dann die APPINSTALLER-Datei an Ihre Endbenutzer und lassen sie auf diese anstatt auf die MSIX-Datei doppelklicken, um die verpackte App zu installieren.

Continuous Deployment

Die App-Installer-Datei selbst ist eine unkompilierte XML-Datei, die nach dem Buildvorgang bei Bedarf bearbeitet werden kann. Dies erleichtert die Verwendung, wenn Sie Ihre Software in mehreren Umgebungen bereitstellen und die Buildpipeline vom Releaseprozess trennen möchten.

Wenn Sie eine Releasepipeline im Azure-Portal mit der Vorlage „Leere Stufe“ erstellen und die kürzlich eingerichtete Buildpipeline als Quelle für das bereitzustellende Artefakt verwenden (wie in Abbildung 6 gezeigt), können Sie der Releasestufe den PowerShell-Task in Abbildung 7 hinzufügen, um die Werte der beiden Uri-Attribute in der APPINSTALLER-Datei dynamisch zu ändern, um den Speicherort der App wiederzugeben.

Die Registerkarte „Pipeline“ im Azure DevOps-Portal
Abbildung 6: Die Registerkarte „Pipeline“ im Azure DevOps-Portal

Abbildung 7A: Ein Releasepipelinetask, der die URIs in der APPINSTALLER-Datei ändert

- powershell: |
  [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
  $fileShare = "\\filesharestorageccount.file.core.windows.net\myfileshare\"
  $localFilePath =
    "$(System.DefaultWorkingDirectory)\_MsixDesktopApp\drop\MsixDesktopApp.appinstaller"
  $doc = [System.Xml.Linq.XDocument]::Load("$localFilePath")
  $doc.Root.Attribute("Uri").Value = [string]::Format('{0}{1}', $fileShare,
    'MsixDesktopApp.appinstaller')
  $xName =
    [System.Xml.Linq.XName]"{http://schemas.microsoft.com/appx/appinstaller/2018}MainPackage"
  $doc.Root.Element($xName).Attribute("Uri").Value = [string]::Format('{0}{1}',
    $fileShare, 'MsixDesktopApp.appx')
  $doc.Save("$localFilePath")
displayName: 'Modify URIs in App Installer File'

Im Task in Abbildung7 wird der URI auf den UNC-Pfad einer Azure-Dateifreigabe festgelegt. Da dies der Speicherort ist, an dem das Betriebssystem nach dem MSIX-Paket sucht, wenn Sie die App installieren und aktualisieren, habe ich der Releasepipeline auch ein weiteres Befehlszeilenskript hinzugefügt, das zuerst die Dateifreigabe in der Cloud dem lokalen Laufwerk „Z:\“ auf dem Build-Agent zuordnet, bevor es den xcopy-Befehl verwendet, um die APPINSTALLER- und MSIX-Dateien zu kopieren:

- script: |
  net use Z: \\filesharestorageccount.file.core.windows.net\myfileshare
    /u:AZURE\filesharestorageccount
    3PTYC+ociHIwNgCnyg7zsWoKBxRmkEc4Aew4FMzbpUl/
    dydo/3HVnl71XPe0uWxQcLddEUuq0fN8Ltcpc0LYeg==
  xcopy $(System.DefaultWorkingDirectory)\_MsixDesktopApp\drop Z:\ /Y
  displayName: 'Publish App Installer File and MSIX package'

Wenn Sie Ihren eigenen lokalen Azure DevOps Server hosten, können Sie die Dateien natürlich auch in Ihrer eigenen internen Netzwerkfreigabe veröffentlichen.

Webinstallationen: Wenn Sie sich für die Veröffentlichung auf einem Webserver entscheiden, können Sie MSBuild anweisen, eine mit einer Versionsangabe versehene APPINSTALLER-Datei und eine HTML-Seite zu generieren, die einen Downloadlink und einige Informationen zur verpackten Anwendung enthält, indem Sie einige zusätzliche Argumente in der YAML-Datei angeben:

- task: MSBuild@1
  inputs:
    solution: Msix/Msix.wapproj
    platform: $(buildPlatform)
    configuration: $(buildConfiguration)
    msbuildArguments: '/p:OutputPath=NonPackagedApp /p:UapAppxPackageBuildMode=SideLoadOnly  /p:AppxBundle=Never /p:GenerateAppInstallerFile=True
/p:AppInstallerUri=http://yourwebsite.com/packages/ /p:AppInstallerCheckForUpdateFrequency=OnApplicationRun /p:AppInstallerUpdateFrequency=1 /p:AppxPackageDir=$(Build.ArtifactStagingDirectory)/'
  displayName: 'Package the App'

Abbildung 8 zeigt den Inhalt des Stagingverzeichnisses auf dem Build-Agent nach der Ausführung des vorherigen Befehls. Es handelt sich um die gleiche Ausgabe, die Sie vom Assistenten in Visual Studio erhalten, wenn Sie Pakete für das Querladen erstellen und das Kontrollkästchen „Automatische Updates aktivieren“ aktivieren. Mit diesem Ansatz können Sie die manuell erstellte APPINSTALLER-Datei auf Kosten einer gewissen Flexibilität bei der Konfiguration des Aktualisierungsverhaltens entfernen.

Der Buildartefakten-Explorer im Azure DevOps-Portal
Abbildung 8: Der Buildartefakten-Explorer im Azure DevOps-Portal

Die generierte HTML-Datei enthält einen Link, dem das browserunabhängige Protokollaktivierungsschema ms-appinstaller als Präfix vorangestellt ist:

<a href="ms-appinstaller:?source=
  http://yourwebsite.com/packages/Msix_x86.appinstaller ">Install App</a>

Wenn Sie eine Releasepipeline einrichten, die den Inhalt des Ablageordners in Ihrem Intranet oder auf einer anderen Website veröffentlicht, und der Webserver Bytebereichsanfragen unterstützt und ordnungsgemäß konfiguriert ist, können Ihre Endbenutzer über diesen Link die App direkt installieren, ohne vorher das MSIX-Paket herunterzuladen.

Zusammenfassung

In diesem Artikel haben Sie gesehen, wie einfach es ist, eine .NET-Desktopanwendung mit Visual Studio als MSIX-Datei zu verpacken. Sie haben auch gesehen, wie CI- und CD-Pipelines in Azure Pipelines eingerichtet und automatische Updates konfiguriert werden. MSIX ist der moderne Weg, um Anwendungen unter Windows bereitzustellen. Das Format ist so konzipiert, dass es sicher, unbedenklich und zuverlässig ist. Es ermöglicht Ihnen und Ihren Kunden, die Vorteile des neuen App-Modells und der modernen APIs zu nutzen, die in Windows 10 eingeführt wurden, und zwar unabhängig davon, ob Sie Ihre Apps in den Microsoft Store hochladen oder sie auf Computer in Ihrem Unternehmen querladen möchten. Wenn alle Ihre Benutzer auf Windows 10 umgestiegen sind, sollten Sie in der Lage sein, MSIX zu nutzen, um die meisten Windows-Desktopanwendungen zu verpacken, die es gibt.


Magnus Montinist ein Microsoft MVP, der als selbständiger Softwareentwickler und Berater in Stockholm (Schweden) arbeitet. Seine Spezialgebiete sind .NET und der Microsoft-Stapel, und er verfügt über mehr als ein Jahrzehnt an praktischer Erfahrung. Seinen Blog finden Sie unter blog.magnusmontin.net.

Unser Dank gilt dem folgenden technischen Experten bei Microsoft für die Durchsicht dieses Artikels: Matteo Pagani (Matteo.Pagani@microsoft.com)
Matteo Pagani ist ein Entwickler mit einer großen Leidenschaft für Cliententwicklung und die Windows-Plattform. Er ist regelmäßiger Referent auf Konferenzen auf der ganzen Welt. Außerdem ist er Buchautor und schreibt regelmäßig Fachartikel für technische Websites und Blogs. Er war 5 Jahre lang Microsoft MVP in der Kategorie Windows-Entwicklung. Danach verstärkte er das Windows AppConsult-Team von Microsoft als Engineer.


Diesen Artikel im MSDN Magazine-Forum diskutieren