Plattformübergreifende NuGet-Plug-Ins

In NuGet 4.8 und höher wurde Unterstützung für plattformübergreifende Plug-Ins hinzugefügt. Dies wurde durch das Entwickeln eines neuen Plug-in-Erweiterbarkeitsmodells erreicht, das einem strengen Satz von Vorgangsregeln genügen muss. Die Plug-Ins sind eigenständige ausführbare Dateien („Runnables“ im .NET Core-Sprachgebrauch), die von den NuGet-Clients in einem separaten Prozess gestartet werden. Es handelt sich um echte Plug-Ins vom Typ „write once, run everywhere“. Sie funktionieren mit allen NuGet-Clienttools. Die Plug-Ins können vom Typ .NET Framework („NuGet.exe“, „msbuild.exe“ und Visual Studio) oder .NET Core („dotnet.exe“) sein. Ein Kommunikationsprotokoll mit Versionsangabe ist zwischen dem NuGet-Client und dem Plug-In definiert. Während des Starthandshakes handeln die beiden Prozesse die Protokollversion aus.

Um alle Szenarien für NuGet-Clienttools abzudecken, benötigen Sie ein .NET Framework- und ein .NET Core-Plug-In. Im Folgenden werden die Client-/Frameworkkombinationen der Plug-Ins beschrieben.

Clienttool Framework
Visual Studio .NET Framework
dotnet.exe .NET Core
NuGet.exe .NET Framework
MSBuild.exe .NET Framework
NuGet.exe unter Mono .NET Framework

Wie funktioniert das?

Der allgemeine Workflow kann wie folgt beschrieben werden:

  1. NuGet erkennt verfügbare Plug-Ins.
  2. Wenn zutreffend, durchläuft NuGet die Plug-Ins in der Reihenfolge der Priorität und startet sie nacheinander.
  3. NuGet verwendet das erste Plug-In, das die Anforderung bedienen kann.
  4. Die Plug-Ins werden heruntergefahren, wenn sie nicht mehr benötigt werden.

Allgemeine Plug-In-Anforderungen

Die aktuelle Protokollversion ist 2.0.0. Unter dieser Version gelten die folgenden Anforderungen:

  • Es sind gültige, vertrauenswürdige Authenticode-Signaturassemblys vorhanden, die unter Windows und Mono ausgeführt werden. Für Assemblys, die unter Linux und Mac ausgeführt werden, ist keine besondere Vertrauensstellung erforderlich. Relevantes Problem
  • Unterstützung des zustandslosen Starts im aktuellen Sicherheitskontext der NuGet-Clienttools. Beispielsweise führen die NuGet-Clienttools keine Erhöhung von Rechten oder zusätzliche Initialisierung außerhalb des später beschriebenen Plug-In-Protokolls aus.
  • Nicht interaktives Verhalten, wenn nicht explizit angegeben.
  • Verwenden der ausgehandelten Plug-In-Protokollversion.
  • Reagieren auf alle Anforderungen innerhalb eines angemessenen Zeitraums.
  • Beachten von Abbruchanforderungen für alle aktuell ausgeführten Vorgänge.

Die technische Spezifikation wird in den folgenden Spezifikationen ausführlicher beschrieben:

Interaktion zwischen Client und Plug-In

Die NuGet-Clienttools und die Plug-Ins kommunizieren mit JSON über Standardstreams (stdin, stdout, stderr). Alle Daten müssen UTF-8-codiert sein. Die Plug-Ins werden mit dem Argument „-Plugin“ gestartet. Wenn ein Benutzer eine ausführbare Plug-In-Datei ohne dieses Argument direkt startet, kann das Plug-In eine informative Nachricht ausgeben, anstatt auf einen Protokollhandshake zu warten. Das Timeout für den Protokollhandshake beträgt 5 Sekunden. Das Plug-In sollte das Setup in möglichst kurzer Zeit abschließen. NuGet-Clienttools fragen die von einem Plug-In unterstützten Vorgänge ab, indem sie den Dienstindex für eine NuGet-Quelle übergeben. Ein Plug-In kann den Dienstindex verwenden, um das Vorhandensein von unterstützten Diensttypen zu überprüfen.

Die Kommunikation zwischen den NuGet-Clienttools und dem Plug-In ist bidirektional. Jede Anforderung hat ein Timeout von 5 Sekunden. Wenn Vorgänge länger dauern sollen, sollte der jeweilige Prozess eine Statusmeldung senden, um zu verhindern, dass die Anforderung eine Zeitüberschreitung auslöst. Nach 1 Minute Inaktivität gilt ein Plug-in als im Leerlauf und wird heruntergefahren.

Installation und Ermittlung von Plug-Ins

Die Plug-Ins werden über eine auf Konventionen basierende Verzeichnisstruktur ermittelt. CI/CD-Szenarien und Poweruser können Umgebungsvariablen verwenden, um das Verhalten zu überschreiben. Wenn Umgebungsvariablen verwendet werden, sind nur absolute Pfade zulässig. Beachten Sie, dass NUGET_NETFX_PLUGIN_PATHS und NUGET_NETCORE_PLUGIN_PATHS nur mit Version 5.3 oder höher der NuGet-Tools verfügbar sind.

  • NUGET_NETFX_PLUGIN_PATHS: Definiert die Plug-Ins, die von den auf .NET Framework basierenden Tools (nuget.exe/msbuild.exe/Visual Studio) verwendet werden. Besitzt Vorrang vor NUGET_PLUGIN_PATHS. (Nur NuGet-Version 5.3 oder höher)
  • NUGET_NETCORE_PLUGIN_PATHS: Definiert die Plug-Ins, die von den auf .NET Core basierenden Tools (dotnet.exe) verwendet werden. Besitzt Vorrang vor NUGET_PLUGIN_PATHS. (Nur NuGet-Version 5.3 oder höher)
  • NUGET_PLUGIN_PATHS: Definiert die Plug-Ins, die für den NuGet-Prozess verwendet werden. Die Priorität wird beibehalten. Wenn diese Umgebungsvariable festgelegt ist, wird die auf der Konvention basierende Ermittlung überschrieben. Wird ignoriert, wenn eine der frameworkspezifischen Variablen angegeben wird.
  • User-location, der NuGet-Startspeicherort in %UserProfile%/.nuget/plugins. Dieser Speicherort kann nicht überschrieben werden. Für .NET Core- und .NET Framework-Plug-Ins wird ein anderes Stammverzeichnis verwendet.
Framework Ermittlung des Stammverzeichnisses
.NET Core %UserProfile%/.nuget/plugins/netcore
.NET Framework %UserProfile%/.nuget/plugins/netfx

Jedes Plug-In sollte in einem eigenen Ordner installiert werden. Der Plug-In-Einstiegspunkt ist der Name des installierten Ordners mit der DLL-Erweiterung für .NET Core und der EXE-Erweiterung für .NET Framework.

.nuget
    plugins
        netfx
            myPlugin
                myPlugin.exe
                nuget.protocol.dll
                ...
        netcore
            myPlugin
                myPlugin.dll
                nuget.protocol.dll
                ...

Hinweis

Zurzeit gibt es keine User Story für die Installation der Plug-Ins. Die Installation ist ganz einfach: Sie verschieben die erforderlichen Dateien an den vordefinierten Speicherort.

Unterstützte Vorgänge

Unter dem neuen Plug-In-Protokoll werden zwei Vorgänge unterstützt.

Vorgangsname Mindestprotokollversion Mindestversion des NuGet-Clients
Downloadpaket 1.0.0 4.3.0
Authentifizierung 2.0.0 4.8.0

Ausführen von Plug-Ins unter der richtigen Laufzeit

Für NuGet in dotnet.exe-Szenarien müssen Plug-Ins unter dieser bestimmten Laufzeit von „dotnet.exe“ ausgeführt werden können. Der Plug-In-Anbieter und der Consumer sind für die Sicherstellung verantwortlich, dass eine kompatible Kombination aus „dotnet.exe“ und Plug-In verwendet wird. Ein potenzielles Problem könnte bei den user-location-Plug-Ins auftreten, wenn beispielsweise eine Datei „dotnet.exe“ unter der 2.0-Laufzeit versucht, ein für die 2.1-Laufzeit geschriebenes Plug-In zu verwenden.

Zwischenspeichern von Funktionen

Die Sicherheitsüberprüfung und die Instanziierung der Plug-Ins ist speicherintensiv. Der Downloadvorgang erfolgt viel häufiger als der Authentifizierungsvorgang, aber der durchschnittliche NuGet-Benutzer verfügt wahrscheinlich nur über ein Authentifizierungs-Plug-In. Um die Benutzererfahrung zu optimieren, speichert NuGet die Ansprüche der Vorgänge für die jeweilige Anforderung zwischen. Dieser Cache gilt pro Plug-In. Dabei ist der Plug-In-Schlüssel der Plug-In-Pfad, und der Ablaufzeitraum für diesen Funktionscache beträgt 30 Tage.

Der Cache befindet sich in %LocalAppData%/NuGet/plugins-cache und wird durch die Umgebungsvariable NUGET_PLUGINS_CACHE_PATH überschrieben. Zum Löschen dieses Caches können Sie den locals-Befehl mit der Option plugins-cache ausführen. Mit der locals-Option all wird nun auch der Plug-In-Cache gelöscht.

Protokollnachrichtenindex

Nachrichten der Protokollversion 1.0.0:

  1. Schließen

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält keine Nutzlast
    • Es wird keine Antwort erwartet. Die richtige Antwort besteht darin, dass der Plug-In-Prozess umgehend beendet wird.
  2. Kopieren der Dateien im Paket

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • ID und Version des Pakets
      • Speicherort des Quellrepositorys des Pakets
      • Pfad des Zielverzeichnisses
      • Aufzählbares Element von Dateien im Paket, die in den Zielverzeichnispfad kopiert werden sollen
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Aufzählbares Element der vollständigen Pfade für kopierte Dateien im Zielverzeichnis, wenn der Vorgang erfolgreich war
  3. Kopieren der Paketdatei (NUPKG-Datei)

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • ID und Version des Pakets
      • Speicherort des Quellrepositorys des Pakets
      • Zieldateipfad
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
  4. Abrufen von Anmeldeinformationen

    • Anfordern der Richtung: Plugin -> NuGet
    • Die Anforderung enthält Folgendes:
      • Speicherort des Quellrepositorys des Pakets
      • HTTP-Statuscode, der mit den aktuellen AnmeldeiInformationen aus dem Quellrepository des Pakets abgerufen wurde
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Benutzername, falls verfügbar
      • Kennwort, falls verfügbar
  5. Abrufen von Dateien im Paket

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • ID und Version des Pakets
      • Speicherort des Quellrepositorys des Pakets
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Aufzählbares Element der Dateipfade im Paket, wenn der Vorgang erfolgreich war
  6. Abrufen von Ansprüchen des Vorgangs

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • „index.json“ des Diensts für eine Paketquelle
      • Speicherort des Quellrepositorys des Pakets
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Aufzählbares Element unterstützter Vorgänge (z. B. Paketdownload), wenn der Vorgang erfolgreich war. Wenn ein Plug-In die Paketquelle nicht unterstützt, muss das Plug-In einen leeren Satz unterstützter Vorgänge zurückgeben.

Hinweis

Diese Meldung wurde in Version 2.0.0 aktualisiert. Sie ist auf dem Client vorhanden, um die Abwärtskompatibilität aufrechtzuerhalten.

  1. Abrufen des Pakethash

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • ID und Version des Pakets
      • Speicherort des Quellrepositorys des Pakets
      • Hashalgorithmus
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Paketdateihash, der den angeforderten Hashalgorithmus verwendet, wenn der Vorgang erfolgreich war
  2. Abrufen von Paketversionen

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • Paket-ID
      • Speicherort des Quellrepositorys des Pakets
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Aufzählbares Element der Paketversionen, wenn der Vorgang erfolgreich war
  3. Abrufen des Dienstindex

    • Anfordern der Richtung: Plugin -> NuGet
    • Die Anforderung enthält Folgendes:
      • Speicherort des Quellrepositorys des Pakets
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Dienstindex, wenn der Vorgang erfolgreich war
  4. Handschlag

    • Anfordern der Richtung: NuGet <-> Plugin
    • Die Anforderung enthält Folgendes:
      • Aktuelle Protokollversion des Protokoll-Ins
      • Mindestens unterstützte Plug-In-Protokollversion
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Ausgehandelte Protokollversion, wenn der Vorgang erfolgreich war. Ein Fehler führt zu einer Beendigung des Plug-ins.
  5. Initialize

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • Version des NuGet-Clienttools
      • Effektive Sprache des NuGet-Clienttools. Dabei wird die Einstellung ForceEnglishOutput berücksichtigt, wenn vorhanden.
      • Standardtimeout der Anforderung, das Vorrang vor dem Standardwert des Protokolls besitzt.
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt. Ein Fehler führt zu einer Beendigung des Plug-ins.
  6. Log

    • Anfordern der Richtung: Plugin -> NuGet
    • Die Anforderung enthält Folgendes:
      • Protokollebene für die Anforderung
      • Zu protokollierende Nachricht
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt.
  7. Überwachen der Beendigung eines NuGet-Prozesses

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • NuGet-Prozess-ID
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt.
  8. Vorababruf eines Pakets

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • ID und Version des Pakets
      • Speicherort des Quellrepositorys des Pakets
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
  9. Anmeldeinformationen festlegen

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • Speicherort des Quellrepositorys des Pakets
      • Benutzername der letzten bekannten Paketquelle, falls verfügbar
      • Kennwort der letzten bekannten Paketquelle, falls verfügbar
      • Benutzername des letzten bekannten Proxys, falls verfügbar
      • Kennwort des letzten bekannten Proxys, falls verfügbar
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
  10. Festlegen der Protokollierungsebene

    • Anfordern der Richtung: NuGet -> Plugin
    • Die Anforderung enthält Folgendes:
      • Standardprotokollebene
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt

Nachrichten der Protokollversion 2.0.0

  1. Abrufen von Ansprüchen des Vorgangs
  • Anfordern der Richtung: NuGet -> Plugin

    • Die Anforderung enthält Folgendes:
      • „index.json“ des Diensts für eine Paketquelle
      • Speicherort des Quellrepositorys des Pakets
    • Eine Antwort enthält Folgendes:
      • Antwortcode, der das Ergebnis des Vorgangs angibt
      • Aufzählbares Element unterstützter Vorgänge, wenn der Vorgang erfolgreich war. Wenn ein Plug-In die Paketquelle nicht unterstützt, muss das Plug-In einen leeren Satz unterstützter Vorgänge zurückgeben.

    Wenn der Dienstindex und die Paketquelle NULL sind, kann das Plug-In mit Authentifizierung antworten.

  1. Abrufen der Anmeldeinformationen für die Authentifizierung
  • Anfordern der Richtung: NuGet -> Plugin
  • Die Anforderung enthält Folgendes:
    • Uri
    • isRetry
    • NonInteractive
    • CanShowDialog
  • Eine Antwort enthält Folgendes
    • Benutzername
    • Kennwort
    • `Message`
    • Liste der Authentifizierungstypen
    • MessageResponseCode