Freigeben über


Datenspeicher

Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2019

Azure DevOps-Erweiterungen können Benutzereinstellungen und komplexe Datenstrukturen direkt in der von Microsoft bereitgestellten Infrastruktur speichern, wodurch sichergestellt wird, dass die Daten Ihres Benutzers wie andere Organisations- und Projektdaten sicher und gesichert sind. Dies bedeutet auch für einfache Datenspeicheranforderungen, Dass Sie als Erweiterungsanbieter nicht erforderlich sind, um Datenspeicherdienste von Drittanbietern einzurichten, zu verwalten oder zu bezahlen.

Es gibt zwei Methoden für die Interaktion mit dem Datenspeicherdienst: über REST-APIs oder über einen von Microsoft bereitgestellten Clientdienst, der Teil des VSS SDK ist. Wir empfehlen Erweiterungsentwicklern, die bereitgestellten Clientdienst-APIs zu nutzen, da sie eine benutzerfreundliche Kapselung der REST-APIs bieten.

Hinweis

Suchen Sie nach Azure DevOps REST-APIs? Weitere Informationen finden Sie in der neuesten Referenz zur Azure DevOps REST-API.

Informationen zu .NET-Clientbibliotheken finden Sie unter .NET-Clientbibliotheken für Azure DevOps.

Was Sie speichern können

Der Dienst ist so konzipiert, dass Sie zwei verschiedene Datentypen speichern und verwalten können:

  • Einstellungen: Einfache Schlüsselwerteinstellungen (z. B. Benutzereinstellungen)
  • Dokumente: Sammlungen ähnlicher komplexer Objekte (Dokumente)

Eine Auflistung ist ein indiziertes Container für Dokumente. Ein Dokument ist ein JSON-Blob, das zu einer Auflistung gehört. Abgesehen von einigen reservierten Eigenschaftennamen steuern und verwalten Sie das Schema dieser Dokumente.

Wie Sie Datenbereich festlegen können

Einstellungen und Dokumentsammlungen können auf die folgenden Bereiche angewendet werden:

  • Projektsammlung: von allen Benutzern der Projektsammlung gemeinsam verwendet, auf die die Erweiterung installiert ist
  • Benutzer: ein einzelner Benutzer einer Projektsammlung, in der die Erweiterung installiert ist

Einstellungen Speicher

Die beiden Standard Methoden zum Verwalten von Einstellungen sind getValue() undsetValue():

  • getValue() akzeptiert eine Zeichenfolgentaste (zusammen mit anderen Optionen wie Bereich) und gibt eine IPromise zurück. Der aufgelöste Wert dieser Zusage ist der dem bereitgestellten Schlüssel zugeordnete Wert.
  • setValue() akzeptiert einen Zeichenfolgenschlüssel, einen Wert und andere Optionen, z. B. Bereich, und gibt eine IPromise zurück. Der aufgelöste Wert dieser Zusage ist der aktualisierte Wert der Einstellung.

Hier ist ein Beispiel für das Festlegen eines Werts:

        private async initializeState(): Promise<void> {
        await SDK.ready();
        const accessToken = await SDK.getAccessToken();
        const extDataService = await SDK.getService<IExtensionDataService>(CommonServiceIds.ExtensionDataService);
        this._dataManager = await extDataService.getExtensionDataManager(SDK.getExtensionContext().id, accessToken);

        this._dataManager.getValue<string>("test-id").then((data) => {
            this.setState({
                dataText: data,
                persistedText: data,
                ready: true
            });
        }, () => {
            this.setState({
                dataText: "",
                ready: true
            });
        });
    }

Hier ist ein Beispiel für das Abrufen eines Einstellungswerts:

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        // Get value in user scope
        dataService.getValue("userScopedKey", {scopeType: "User"}).then(function(value) {
            console.log("User scoped key value is " + value);
        });
    });

Wenn scopeType nicht angegeben, werden die Einstellungen auf Projektsammlungsebene gespeichert und können über die Erweiterung für alle Benutzer in dieser Projektsammlung zugänglich sein. Hier ist ein Beispiel für das Festlegen eines Einstellungswerts auf Projektsammlungsebene:

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        // Set value (default is project collection scope)
        dataService.setValue("someKey", "abcd-efgh").then(function(value) {
            console.log("Key value is " + value);
        });
    });

Speicherung von Daten (Sammlungen von Dokumenten)

Um komplexere Daten über Schlüsselwertpaare hinaus zu verarbeiten, können Sie das Konzept von Dokumenten verwenden, um CRUD-Vorgänge für die Daten Ihrer Erweiterung auszuführen. Ein Dokument ist ein JSON-Blob, das mit zwei speziellen Eigenschaften erweitert wird: ID und __etag. Wenn sie für das Datenmodell einer Erweiterung von entscheidender Bedeutung sind, können IDs benutzerdefinierter oder nicht angegebener Elemente vom System generiert werden. Diese IDs müssen innerhalb einer bestimmten Sammlung eindeutig sein. Da eine Auflistung auf einen bestimmten Bereich und eine bestimmte Instanz einer Erweiterung verweist, bedeutet dies, dass dieselbe Dokument-ID in verschiedenen Auflistungen wiederverwendet werden kann.

Die folgenden Dokumentvorgänge sind verfügbar:

  • Abrufen eines Dokuments
  • Erstellen eines Dokuments
  • Festlegen eines Dokuments (Erstellen oder Aktualisieren)
  • Aktualisieren eines Dokuments
  • Ein Dokument löschen

Es gibt auch einen einzelnen Vorgang, der für eine Sammlung ausgeführt werden kann: Abrufen aller Dokumente

Abrufen eines Dokuments nach ID

Das Abrufen eines Dokuments aus einer Auflistung mithilfe seines Bezeichners ist einfach, wie im folgenden Beispiel:

    // Acquire data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        // Retrieve document by id
        dataService.getDocument("MyCollection", "MyDocumentId").then(function(doc) {
            // Assuming document has a property named foo
            console.log("Doc foo: " + doc.foo);
        });
    });

Dieser Vorgang versucht, ein Dokument mit der ID "MyDocumentId" aus der "MyCollection"-Auflistung abzurufen. Wenn kein bereitgestellter Bereich vorhanden ist, verwendet der Dienst standardmäßig die Auflistung, die auf die gesamte Instanz dieser Erweiterung festgelegt ist. Wenn entweder diese Auflistung oder ein Dokument mit der angegebenen ID nicht vorhanden ist, wird ein 404-Fehler zurückgegeben, der von der Erweiterung behandelt werden soll. Das zurückgegebene Dokument ist ein JSON-Objekt, das alle Eigenschaften enthält, zusammen mit der speziellen ID und __etag den Eigenschaften, die vom Datenspeicherdienst verwendet werden.

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        // Get document by id
        dataService.getDocument("MyCollection", "MyDocumentId").then(function(doc) {
            // Assuming document has a property named foo
            console.log("Doc foo: " + doc.foo);
        });
    });

Dieser Aufruf versucht, ein Dokument mit der ID "MyDocumentId" aus der Sammlung "MyCollection" abzurufen. Da kein Bereich bereitgestellt wird, wird die vom Dienst verwendete Auflistung auf den Standardwert der gesamten Instanz dieser Erweiterung festgelegt. Wenn diese Auflistung nicht vorhanden ist oder ein Dokument mit dieser ID nicht vorhanden ist, wird eine 404 zurückgegeben, die von der Erweiterung behandelt werden soll. Das zurückgegebene Dokument ist ein JSON-Objekt, das alle eigenen Eigenschaften enthält, zusätzlich zu der speziellen ID und __etag eigenschaften, die vom Datenspeicherdienst verwendet werden.

Erstellen eines Dokuments

Führen Sie zum Erstellen eines neuen Dokuments einen Aufruf wie das folgende Beispiel aus:

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        // Prepare document first
        var newDoc = {
            fullScreen: false,
            screenWidth: 500
        };

        dataService.createDocument("MyCollection", newDoc).then(function(doc) {
            // Even if no ID was passed to createDocument, one gets generated
            console.log("Doc id: " + doc.id);
        });
    });

Wenn die Auflistung mit dem angegebenen Namen und dem angegebenen Bereich noch nicht vorhanden ist, wird sie dynamisch erstellt, bevor das Dokument selbst erstellt wird.

Wenn das bereitgestellte Dokument eine id Eigenschaft enthält, wird dieser Wert als eindeutige ID für das Dokument verwendet. Bitte beachten Sie, dass die bereitgestellten id Zeichen auf 50 Zeichen beschränkt sein sollten. Wenn dieses Feld nicht vorhanden ist, wird eine GUID vom Dienst generiert und in das Dokument einbezogen, das zurückgegeben wird, wenn die Zusage aufgelöst wird.

Wenn bereits ein anderes Dokument in der Auflistung mit derselben ID wie die im Dokument angegebene vorhanden ist, schlägt der Vorgang fehl. Wenn das gewünschte Verhalten ein neues Dokument erstellt, wenn die ID nicht vorhanden ist, aber das vorhandene Dokument ändern, falls dies der Fall ist, sollte die setDocument() Methode verwendet werden.

Festlegen eines Dokuments (Aktualisieren oder Erstellen)

Die setDocument() Funktion führt einen "Upsert"-Vorgang aus– es ändert ein vorhandenes Dokument, wenn seine ID vorhanden ist und einem Dokument in der Auflistung entspricht. Wenn die ID nicht vorhanden ist oder keinem Dokument in der Auflistung entspricht, wird der Auflistung ein neues Dokument hinzugefügt.

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        // Prepare document first
        var myDoc = {
            id: 1,
            fullScreen: false,
            screenWidth: 500
        };

        dataService.setDocument("MyCollection", myDoc).then(function(doc) {
            console.log("Doc id: " + doc.id);
        });
    });

Aktualisieren eines Dokuments

Die updateDocument Funktion erfordert, dass sich das Dokument, das geändert wird, bereits in der Auflistung befindet. Eine Ausnahme wird ausgelöst, wenn keine ID angegeben wird oder die angegebene ID keinem Dokument in der Auflistung entspricht.

Hier ist ein Beispiel für die Verwendung von Updates:

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        var collection = "MyCollection";
        var docId = "1234-4567-8910";
        // Get document first
        dataService.getDocument(collection, docId, { scopeType: "User" }).then(function(doc) {
            // Update the document
            doc.name = "John Doe";
            dataService.updateDocument(collection, doc, { scopeType: "User" }).then(function(d) {
                // Check the new version
                console.log("Doc version: " + d.__etag);
            });
        });
    });

Ein Dokument löschen

Diese Funktion löscht das Dokument mit der bereitgestellten ID aus der bereitgestellten Auflistung. Wenn die Auflistung nicht vorhanden ist oder das Dokument nicht vorhanden ist, wird ein 404 zurückgegeben.

Beispiel zur Verwendung:

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        var docId = "1234-4567-8910";
        // Delete document
        dataService.deleteDocument("MyCollection", docId).then(function() {
            console.log("Doc deleted");
        });
    });

Abrufen aller Dokumente in einer Sammlung

Im folgenden Beispiel werden alle Dokumente aus der "MyCollection"-Auflistung mithilfe des Datendiensts abgerufen und dann die Anzahl der Dokumente in der Konsole protokolliert:

    // Get data service
    SDK.getService(SDK.getContributionId()).then(function(dataService) {
        // Get all document under the collection
        dataService.getDocuments("MyCollection").then(function(docs) {
            console.log("There are " + docs.length + " in the collection.");
        });
    });

Mit diesem Aufruf werden alle Dokumente in einer bereichsbezogenen Auflistung mit einem Grenzwert von 100.000 Dokumenten abgerufen. Wenn die Auflistung nicht vorhanden ist, wird ein 404-Fehler zurückgegeben.

Erweitert

Wie Einstellungen gespeichert werden

Dieser Aufruf kapselt die setDocument Clientmethode und stellt sie mit mehreren Datenteilen zur Verfügung. Wie bereits erwähnt, werden Einstellungen intern als Dokumente gespeichert. Daher wird ein einfaches Dokument dynamisch generiert, wobei die ID des Dokuments der Schlüssel in der setValue() Methode ist. Das Dokument verfügt über zwei weitere Eigenschaften. Die value Eigenschaft enthält den an die Methode übergebenen Wert, und die revision Eigenschaft wird auf -1. revision Die Eigenschaft wird zwar im Abschnitt "Arbeiten mit Dokumenten" weiter ausgearbeitet, im Kontext der Einstellungen bedeutet die Einstellung revision -1 im Dokument jedoch, dass wir uns nicht mit der Versionsverwaltung dieses Einstellungsdokuments befassen.

Da Einstellungen als Dokumente gespeichert werden, müssen wir einen Sammlungsnamen angeben, der angibt, wo das Dokument gespeichert werden soll. Um die Dinge einfach zu halten, ist der Sammlungsname beim Arbeiten mit den setValue()/getValue() Methoden immer der spezielle Name.$settings Der vorherige Aufruf gibt eine PUT-Anforderung am folgenden Endpunkt aus:

GET _apis/ExtensionManagement/InstalledExtensions/{publisherName}/{extensionName}/Data/Scopes/User/Me/Collections/%24settings/Documents

Die Anforderungsnutzlast entspricht dem folgenden Beispiel:

{
                "id": "myKey",
                "__etag": -1,
                "value": "myValue"
}

REST-APIs

Wenn dieser Codeausschnitt nach dem Festlegen des Werts ausgeführt wird, sollte eine Warnmeldung mit dem Text "Der Wert ist myValue" angezeigt werden. Die getValue-Methode ist erneut ein Wrapper um die REST-APIs, die eine GET-Anforderung an den folgenden Endpunkt ausgeben:

GET _apis/ExtensionManagement/InstalledExtensions/{publisherName}/{extensionName}/Data/Scopes/User/Me/Collections/%24settings/Documents/myKey

Etags

Das __etag Feld wird vom Datenspeicherdienst für die Parallelitätsverwaltung von Dokumenten verwendet. Bevor eine Aktualisierung gespeichert wird, überprüft der Dienst, ob das __etag aktuell gespeicherte Dokument mit dem __etag aktualisierten Dokument übereinstimmt. Wenn sie übereinstimmen, wird dies __etag erhöht, und das aktualisierte Dokument wird an den Aufrufer zurückgegeben. Wenn sie nicht übereinstimmen, gibt es an, dass das dokument, das aktualisiert werden soll, veraltet ist und eine Ausnahme ausgelöst wird. Der Erweiterungs-Writer ist für die ordnungsgemäße Behandlung dieser Ausnahme verantwortlich, entweder durch Abrufen des neuesten __etag Dokuments, Zusammenführen der Änderungen und Wiederholen der Aktualisierung oder durch Benachrichtigen des Benutzers.

Für einige Arten von Dokumenten ist die bereitgestellte Parallelitätsstufe möglicherweise nicht erforderlich, und ein Last-in-Wins-Modell ist möglicherweise besser geeignet. Geben Sie in solchen Fällen beim Bearbeiten des Dokuments -1 als Wert ein __etag , um diese Funktionalität zu kennzeichnen. Der zuvor Erwähnung ed Settings Service verwendet dieses Modell zum Speichern von Einstellungen und Einstellungen.