Udostępnij za pośrednictwem


Magazyn danych

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

Rozszerzenia usługi Azure DevOps mogą przechowywać preferencje użytkownika i złożone struktury danych bezpośrednio w infrastrukturze udostępnionej przez firmę Microsoft, co zapewnia bezpieczeństwo danych użytkownika i tworzenie kopii zapasowych, podobnie jak inne dane organizacji i projektu. Oznacza to również, że w przypadku prostych potrzeb związanych z magazynem danych, jako dostawcy rozszerzeń, nie trzeba konfigurować usług magazynu danych innych firm ani zarządzać nimi.

Istnieją dwie metody angażowania się w usługę magazynu danych: za pośrednictwem interfejsów API REST lub za pośrednictwem usługi klienta udostępnianej przez firmę Microsoft, która jest częścią zestawu VSS SDK. Zalecamy deweloperom rozszerzeń korzystanie z udostępnionych interfejsów API usługi klienta, ponieważ oferują one przyjazną dla użytkownika hermetyzację interfejsów API REST.

Uwaga

Szukasz interfejsów API REST usługi Azure DevOps? Zobacz najnowszą dokumentację interfejsu API REST usługi Azure DevOps.

Aby uzyskać informacje o bibliotekach klienta platformy .NET, zobacz Biblioteki klienta platformy .NET dla usługi Azure DevOps.

Co można przechowywać

Usługa została zaprojektowana tak, aby umożliwiała przechowywanie dwóch różnych typów danych i zarządzanie nimi:

  • Ustawienia: proste ustawienia klucz-wartość (takie jak preferencje użytkownika)
  • Dokumenty: kolekcje podobnych złożonych obiektów (dokumentów)

Kolekcja jest kontenerem indeksowanym dla dokumentów. Dokument jest obiektem blob JSON należącym do kolekcji. Poza kilkoma nazwami zastrzeżonych właściwości można kontrolować schemat tych dokumentów i zarządzać nim.

Jak można ograniczyć zakres danych

Ustawienia i kolekcje dokumentów mogą być ograniczone do następujących elementów:

  • Kolekcja projektów: współużytkowana przez wszystkich użytkowników kolekcji projektów, do której zainstalowano rozszerzenie
  • Użytkownik: pojedynczy użytkownik kolekcji projektu, do której zainstalowano rozszerzenie

magazyn Ustawienia

Dwie główne metody zarządzania ustawieniami to getValue() i setValue():

  • getValue() Akceptuje klucz ciągu (wraz z innymi opcjami, takimi jak zakres) i zwraca wartość IPromise. Rozpoznana wartość tej obietnicy to wartość skojarzona z podanym kluczem.
  • setValue() Akceptuje klucz ciągu, wartość i inne opcje, takie jak zakres, i zwraca wartość IPromise. Rozpoznana wartość tej obietnicy to zaktualizowana wartość ustawienia.

Oto przykład ustawiania wartości:

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

Oto przykład pobierania wartości ustawienia:

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

Jeśli scopeType nie zostanie określony, ustawienia są przechowywane na poziomie kolekcji projektów i są dostępne dla wszystkich użytkowników w tej kolekcji projektów przy użyciu rozszerzenia. Oto przykład ustawiania wartości ustawienia na poziomie kolekcji projektów:

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

Magazyn danych (kolekcji dokumentów)

Aby obsłużyć bardziej złożone dane poza pary klucz-wartość, możesz użyć koncepcji dokumentów do wykonywania operacji CRUD na danych rozszerzenia. Dokument jest obiektem blob JSON, rozszerzonym o dwie właściwości specjalne: ID i __etag. Jeśli mają kluczowe znaczenie dla modelu danych rozszerzenia, identyfikatory mogą być zdefiniowane przez użytkownika lub jeśli nie zostały określone, system je generuje. Te identyfikatory muszą być unikatowe w ramach określonej kolekcji. Ponieważ kolekcja odwołuje się do określonego zakresu i wystąpienia rozszerzenia, oznacza to, że ten sam identyfikator dokumentu może być ponownie używany w różnych kolekcjach.

Dostępne są następujące operacje dokumentu:

  • Pobieranie dokumentu
  • Tworzenie dokumentu
  • Ustawianie dokumentu (tworzenie lub aktualizowanie)
  • Aktualizowanie dokumentu
  • Usuwanie dokumentu

Istnieje również jedna operacja, którą można wykonać w kolekcji: Pobieranie wszystkich dokumentów

Pobieranie dokumentu według identyfikatora

Uzyskiwanie dokumentu z kolekcji przy użyciu jego identyfikatora jest proste, jak w poniższym przykładzie:

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

Ta operacja próbuje pobrać dokument o identyfikatorze "MyDocumentId" z kolekcji "MyCollection". W przypadku braku podanego zakresu usługa domyślnie używa kolekcji w zakresie całego wystąpienia tego rozszerzenia. Jeśli ta kolekcja lub dokument o określonym identyfikatorze nie istnieje, zwracany jest błąd 404, który powinien obsługiwać rozszerzenie. Zwrócony dokument jest obiektem JSON zawierającym wszystkie jego właściwości wraz ze specjalnym identyfikatorem i __etag właściwościami używanymi przez usługę magazynu danych.

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

To wywołanie próbuje pobrać dokument o identyfikatorze "MyDocumentId" z kolekcji "MyCollection". Ponieważ nie podano zakresu, kolekcja używana przez usługę jest określana jako domyślna dla całego wystąpienia tego rozszerzenia. Jeśli ta kolekcja nie istnieje lub dokument o tym identyfikatorze nie istnieje, zwracany jest numer 404, który powinien obsłużyć rozszerzenie. Zwracany dokument jest obiektem JSON zawierającym wszystkie jego właściwości, oprócz specjalnego identyfikatora i __etag właściwości używanych przez usługę magazynu danych.

Tworzenie dokumentu

Aby utworzyć nowy dokument, wykonaj wywołanie podobne do następującego przykładu:

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

Jeśli kolekcja o podanej nazwie i zakresie nie istnieje, zostanie utworzona dynamicznie przed utworzeniem samego dokumentu.

Jeśli podany dokument zawiera id właściwość, ta wartość zostanie użyta jako unikatowy identyfikator dokumentu. Należy pamiętać, że podana wartość id powinna być ograniczona do 50 znaków. Jeśli to pole nie istnieje, identyfikator GUID zostanie wygenerowany przez usługę i uwzględniony w dokumencie zwróconym po rozwiązaniu obietnicy.

Jeśli inny dokument w kolekcji już istnieje o tym samym identyfikatorze co podany w dokumencie, operacja kończy się niepowodzeniem. Jeśli żądane zachowanie jest tworzone nowy dokument, jeśli identyfikator nie istnieje, ale zmodyfikuj istniejący dokument, jeśli tak, setDocument() należy użyć metody.

Ustawianie dokumentu (aktualizowanie lub tworzenie)

Funkcja setDocument() wykonuje operację "upsert" — modyfikuje istniejący dokument, jeśli jego identyfikator jest obecny i pasuje do dokumentu w kolekcji. Jeśli identyfikator jest nieobecny lub nie odpowiada żadnemu dokumentowi w kolekcji, nowy dokument zostanie dodany do kolekcji.

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

Aktualizowanie dokumentu

Funkcja updateDocument wymaga, aby zmieniany dokument znajdował się już w kolekcji. Wyjątek jest zgłaszany, jeśli nie podano żadnego identyfikatora lub jeśli podany identyfikator nie odpowiada żadnemu dokumentowi w kolekcji.

Oto przykład użycia aktualizacji:

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

Usuwanie dokumentu

Ta funkcja usuwa dokument z podanym identyfikatorem z udostępnionej kolekcji. Jeśli kolekcja nie istnieje lub dokument nie istnieje, zwracany jest błąd 404.

Oto przykładowe użycie:

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

Pobieranie wszystkich dokumentów w kolekcji

Poniższy przykład pobiera wszystkie dokumenty z kolekcji "MyCollection" przy użyciu usługi danych, a następnie rejestruje liczbę dokumentów w konsoli:

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

To wywołanie pobiera wszystkie dokumenty w kolekcji o określonym zakresie z limitem 100 000 dokumentów. Jeśli kolekcja nie istnieje, zwraca błąd 404.

Zaawansowani

Jak ustawienia są przechowywane

To wywołanie hermetyzuje metodę setDocument klienta, podając ją przy użyciu wielu fragmentów danych. Jak wspomniano wcześniej, ustawienia są zapisywane wewnętrznie jako dokumenty. W związku z tym podstawowy dokument jest generowany dynamicznie, gdzie identyfikator dokumentu jest kluczem podanym w metodzie setValue() . Dokument ma jeszcze dwie właściwości. Właściwość value przechowuje wartość przekazaną do metody, a revision właściwość jest ustawiona na -1wartość . revision Chociaż właściwość jest bardziej rozbudowana w sekcji "Praca z dokumentami", w kontekście ustawień ustawienie na revision-1 wartość w dokumencie oznacza, że nie zajmujemy się przechowywaniem wersji tego dokumentu ustawień.

Ponieważ ustawienia są przechowywane jako dokumenty, musimy podać nazwę kolekcji wskazującą miejsce przechowywania dokumentu. Aby zachować prostotę, podczas pracy z metodami setValue()/getValue() nazwa kolekcji jest zawsze nazwą specjalną .$settings Poprzednie wywołanie wystawia żądanie PUT w następującym punkcie końcowym:

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

Ładunek żądania jest podobny do następującego przykładu:

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

Interfejsy API REST

Zakładając, że ten fragment kodu jest wykonywany po ustawieniu wartości, powinien zostać wyświetlony komunikat alertu zawierający tekst "Wartość jest myValue". Metoda getValue jest ponownie otoką interfejsów API REST, wysyłając żądanie GET do następującego punktu końcowego:

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

tagi etag

Pole __etag jest używane przez usługę magazynu danych na potrzeby zarządzania współbieżnością dokumentów. Przed zapisaniem aktualizacji usługa sprawdza, czy __etag aktualnie przechowywany dokument jest zgodny ze __etag zaktualizowanym dokumentem. Jeśli są one zgodne, __etag element jest zwiększany, a zaktualizowany dokument zostanie zwrócony do elementu wywołującego. Jeśli nie są one zgodne, oznacza to, że dokument do zaktualizowania jest nieaktualny i zgłaszany jest wyjątek. Składnik zapisywania rozszerzeń jest odpowiedzialny za obsługę tego wyjątku w sposób bezproblemowy, przez pobranie najnowszej wersji __etag dokumentu, scalenie zmian i ponowienie próby aktualizacji lub powiadomienie użytkownika.

W przypadku niektórych typów dokumentów poziom podanej współbieżności może nie być konieczny, a model last-in-wins może być bardziej odpowiedni. W takich przypadkach podczas edytowania dokumentu wprowadź wartość -1 jako __etag wartość, aby oznaczyć tę funkcję. Wcześniej wymieniona usługa ustawień używa tego modelu do przechowywania ustawień i preferencji.