共用方式為


資料存放區

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

Azure DevOps 延伸模組可以直接將使用者喜好設定和複雜的數據結構儲存在 Microsoft 提供的基礎結構上,以確保用戶的數據安全且備份,就像其他組織和專案數據一樣。 這也表示您身為延伸模組提供者的簡單數據儲存需求,不需要設定、管理或支付第三方數據記憶體服務的費用。

有兩種方法可以與數據記憶體服務互動:透過 REST API 或透過 Microsoft 提供的客戶端服務,這是 VSS SDK 的一部分。 我們建議延伸模塊開發人員利用提供的用戶端服務 API,因為它們提供使用者易記的 REST API 封裝。

注意

正在尋找 Azure DevOps REST API? 請參閱最新的 Azure DevOps REST API 參考

如需 .NET 用戶端連結庫的相關信息,請參閱 適用於 Azure DevOps 的 .NET 用戶端連結庫。

您可以儲存的內容

此服務的設計目的是讓您儲存和管理兩種不同類型的數據:

  • 設定:簡單的索引鍵/值設定(例如使用者喜好設定)
  • 檔案:類似複雜物件的集合(檔案)

集合是文件的索引容器。 檔是屬於集合的 JSON Blob。 除了一些保留的屬性名稱之外,您還可以控制和管理這些文件的架構。

如何設定數據範圍

設定 與檔案集合的範圍可以是:

  • 專案集合:由安裝延伸模組之專案集合的所有用戶共用
  • 使用者:安裝延伸模組之專案集合的單一使用者

設定 記憶體

管理設定 getValue() 的兩個主要方法是 和 setValue()

  • getValue() 接受字串索引鍵(以及範圍等其他選項),並傳回 IPromise。 此承諾的解析值是與所提供索引鍵相關聯的值。
  • setValue() 接受字串索引鍵、值和其他選項,例如範圍,並傳回 IPromise。 此承諾的已解析值是設定的更新值。

以下是如何設定值的範例:

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

以下是如何擷取設定值的範例:

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

如果未 scopeType 指定,則設定會儲存在專案集合層級,而且所有使用者都可以使用延伸模組存取該專案集合中的設定。 以下是如何在專案集合層級設定設定值的範例:

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

數據(檔案集合) 記憶體

若要處理索引鍵/值組以外的更複雜的數據,您可以使用檔的概念,對延伸模塊的數據執行 CRUD 作業。 檔是 JSON Blob,增強兩個特殊屬性:識別碼和 __etag。 如果它們對延伸模組的數據模型至關重要,則可以使用者定義的標識碼,或如果未指定標識符,系統就會產生這些標識符。 這些標識碼在特定集合內必須是唯一的。 由於集合是指延伸模組的特定範圍和實例,因此表示可以在不同的集合之間重複使用相同的文件識別碼。

下列檔案作業可供使用:

  • 取得文件
  • 建立文件
  • 設定檔案 (建立或更新)
  • 更新文件
  • 刪除文件

另外還有單一作業可以在集合上執行:取得所有檔

依標識碼取得檔

使用其標識碼從集合取得文件很簡單,如下列範例所示:

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

這項作業會嘗試從 「MyCollection」 集合擷取標識碼為 「MyDocumentId」 的檔。 如果沒有提供的範圍,服務預設會使用範圍限定為此延伸模組之整個實例的集合。 如果這個集合或具有指定標識符的檔不存在,則會傳回 404 錯誤,延伸模組應該處理此錯誤。 傳回的檔是 JSON 物件,其中包含其所有屬性,以及數據記憶體服務所使用的特殊識別碼和 __etag 屬性。

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

此呼叫會嘗試從集合 「MyCollection」 擷取標識碼為 「MyDocumentId」 的檔。由於未提供任何範圍,因此服務所使用的集合會限定為此延伸模組之整個實例的預設值。 如果此集合不存在或標識碼不存在的檔,則會傳回 404,延伸模組應該處理此檔案。 傳回的檔是 JSON 物件,除了數據儲存服務所使用的特殊標識碼和 __etag 屬性之外,還包含它自己的所有屬性。

建立文件

若要建立新檔,請執行類似下列範例的呼叫:

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

如果集合的名稱和範圍尚未存在,則會在檔本身建立之前動態建立。

如果提供的檔包含 屬性,該值會當做檔的唯一 id 標識碼使用。 請注意,提供的 id 應限製為 50 個字元。 如果該欄位不存在,服務會產生 GUID,並包含在解析承諾時所傳回的檔上。

如果集合中的另一份檔已存在,且標識符與檔上提供的標識符相同,則作業會失敗。 如果所需的行為是在標識碼不存在時建立新檔,但如果不存在,請修改現有的檔, setDocument() 則應該使用 方法。

設定檔案 (更新或建立)

setDocument() 式會執行「upsert」作業 - 如果現有文件識別碼存在且符合集合中的檔,則會修改現有的檔。 如果標識碼不存在或未對應至集合中的任何檔,則會將新檔新增至集合。

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

更新文件

updateDocument 式會要求要改變的檔已經位於集合中。 如果未提供任何標識碼,或提供的標識符未對應至集合中的任何檔,則會擲回例外狀況。

以下是如何使用更新的範例:

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

刪除文件

此函式會從提供的集合中刪除具有所提供標識符的檔。 如果集合不存在或檔不存在,則會傳回 404。

以下是範例用法:

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

取得集合中的所有檔

下列範例會使用數據服務從 「MyCollection」 集合擷取所有文件,然後將檔數目記錄到控制台:

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

此呼叫會擷取範圍集合中的所有檔,限製為100,000份檔。 如果集合不存在,則會傳回 404 錯誤。

進階

設定的儲存方式

此呼叫會 setDocument 封裝用戶端方法,並提供多個數據片段。 如先前所述,設定會在內部儲存為檔。 因此,會動態產生基本檔,其中文件的標識碼是 方法中 setValue() 提供的索引鍵。 檔還有兩個屬性。 屬性 value 會儲存傳遞至 方法的值,而 revision 屬性會設定為 -1revision雖然 屬性在 [使用檔] 一節中詳細說明,但在設定的內容中,將 設定為 revision -1 ,表示我們不關心此設定檔的版本設定。

由於設定會儲存為檔,因此我們需要提供集合名稱,指出儲存檔的位置。 若要讓事情保持簡單,使用 setValue()/getValue() 方法時,集合名稱一律是特殊名稱 。$settings 先前的呼叫會在下列端點發出 PUT 要求:

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

要求承載類似下列範例:

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

REST API

假設此代碼段是在設定值之後執行,您應該會看到一則警示訊息,其中包含「此值為 myValue」文字。getValue 方法再次是 REST API 的包裝函式,向下列端點發出 GET 要求:

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

etags

數據 __etag 儲存體 服務會使用欄位進行檔並行管理。 儲存更新之前,服務會 __etag 確認目前儲存檔的 與更新檔的 相符 __etag 。 如果相符,則會 __etag 遞增 ,並將更新的檔傳回給呼叫端。 如果它們不相符,表示要更新的檔已過期,並擲回例外狀況。 延伸模組寫入器負責正常處理此例外狀況,方法是擷取檔的最新 __etag 數據、合併變更,以及重試更新,或通知使用者。

對於某些類型的檔,可能不需要提供的並行層級,而且最後一個 wins 模型可能更合適。 在這種情況下,在編輯檔時,輸入 -1 做為 __etag 表示這項功能的值。 先前提及的設定服務會採用此模型來儲存設定和喜好設定。