다음을 통해 공유


데이터 스토리지

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

Azure DevOps 확장은 사용자 기본 설정 및 복잡한 데이터 구조를 Microsoft에서 제공하는 인프라에 직접 저장할 수 있으므로 다른 조직 및 프로젝트 데이터와 마찬가지로 사용자의 데이터가 안전하고 백업됩니다. 또한 간단한 데이터 스토리지 요구 사항의 경우 확장 공급자로서 타사 데이터 스토리지 서비스를 설정, 관리 또는 지불할 필요가 없습니다.

REST API를 통해 또는 VSS SDK의 일부인 Microsoft에서 제공하는 클라이언트 서비스를 통해 데이터 스토리지 서비스에 참여하는 두 가지 방법이 있습니다. 확장 개발자는 REST API의 사용자 친화적인 캡슐화를 제공하므로 제공된 클라이언트 서비스 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 작업을 실행할 수 있습니다. 문서는 ID 및 __etag.의 두 가지 특수 속성으로 향상된 JSON Blob입니다. 확장의 데이터 모델에 중요한 경우 ID는 사용자 정의일 수 있으며, 지정되지 않은 상태로 두면 시스템에서 ID를 생성합니다. 이러한 ID는 특정 컬렉션 내에서 고유해야 합니다. 컬렉션은 확장의 특정 범위 및 인스턴스를 참조하므로 동일한 문서 ID를 여러 컬렉션에서 다시 사용할 수 있음을 의미합니다.

다음 문서 작업을 사용할 수 있습니다.

  • 문서 가져오기
  • 문서 만들기
  • 문서 설정(만들기 또는 업데이트)
  • 문서 업데이트
  • 문서 삭제

컬렉션에서 수행할 수 있는 단일 작업도 있습니다. 모든 문서 가져오기

ID로 문서 가져오기

다음 예제와 같이 해당 식별자를 사용하여 컬렉션에서 문서를 가져오는 것은 간단합니다.

    // 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" 컬렉션에서 ID가 "MyDocumentId"인 문서를 가져오려고 합니다. 제공된 범위가 없는 경우 서비스는 기본적으로 이 확장의 전체 인스턴스로 범위가 지정된 컬렉션을 사용합니다. 이 컬렉션 또는 지정된 ID가 있는 문서가 없으면 확장에서 처리해야 하는 404 오류가 반환됩니다. 반환된 문서는 데이터 스토리지 서비스에서 사용하는 특수 ID 및 속성과 __etag 함께 모든 속성을 포함하는 JSON 개체입니다.

    // 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" 컬렉션에서 ID가 "MyDocumentId"인 문서를 검색하려고 시도합니다. 범위가 제공되지 않으므로 서비스에서 사용하는 컬렉션은 이 확장의 전체 인스턴스의 기본값으로 범위가 지정됩니다. 이 컬렉션이 없거나 해당 ID가 있는 문서가 없으면 확장에서 처리해야 하는 404가 반환됩니다. 반환되는 문서는 데이터 스토리지 서비스에서 사용하는 특수 ID 및 __etag 속성 외에도 자체 속성을 모두 포함하는 JSON 개체입니다.

문서 만들기

새 문서를 만들려면 다음 예제와 같이 호출을 수행합니다.

    // 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로 사용됩니다. 제공된 id 문자는 50자로 제한해야 합니다. 해당 필드가 없으면 서비스에서 GUID를 생성하고 약속이 해결될 때 반환되는 문서에 포함됩니다.

컬렉션의 다른 문서가 문서에 제공된 문서와 동일한 ID로 이미 있는 경우 작업이 실패합니다. ID가 없는 경우 원하는 동작으로 새 문서를 만들지만 기존 문서를 수정하는 경우 메서드를 setDocument() 사용해야 합니다.

문서 설정(업데이트 또는 만들기)

함수는 setDocument() "upsert" 작업을 수행합니다. 이 함수는 ID가 있고 컬렉션의 문서와 일치하는 경우 기존 문서를 수정합니다. ID가 없거나 컬렉션의 문서에 해당하지 않으면 새 문서가 컬렉션에 추가됩니다.

    // 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 함수를 사용하려면 변경 중인 문서가 컬렉션에 이미 있어야 합니다. ID가 제공되지 않거나 제공된 ID가 컬렉션의 문서에 해당하지 않는 경우 예외가 throw됩니다.

업데이트가 사용되는 방법의 예는 다음과 같습니다.

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

문서 삭제

이 함수는 제공된 컬렉션에서 제공된 ID가 있는 문서를 삭제합니다. 컬렉션이 없거나 문서가 없으면 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 오류가 반환됩니다.

Advanced

설정 저장 방법

이 호출은 클라이언트 메서드를 setDocument 캡슐화하여 여러 데이터 조각을 제공합니다. 앞에서 설명한 대로 설정은 내부적으로 문서로 저장됩니다. 따라서 기본 문서는 동적으로 생성되며 여기서 문서의 ID는 메서드에 setValue() 지정된 키입니다. 문서에는 두 개의 속성이 더 있습니다. 속성은 value 메서드에 전달된 값을 보유하며 revision 속성은 .로 -1설정됩니다. revision 이 속성은 "문서 작업" 섹션에서 자세히 설명하지만, 설정 컨텍스트에서 문서의 설정 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 필드는 Data Storage 서비스에서 문서 동시성 관리에 사용됩니다. 업데이트를 저장하기 전에 서비스는 현재 저장된 문서의 문서가 업데이트된 문서의 문서와 일치하는지 __etag 확인 __etag 합니다. 일치하는 __etag 경우 증분되고 업데이트된 문서가 호출자에게 반환됩니다. 일치하지 않으면 업데이트할 문서가 오래되었으며 예외가 throw됨을 나타냅니다. 확장 작성기는 문서의 최신 __etag 내용을 검색하거나, 변경 내용을 병합하고, 업데이트를 다시 시도하거나, 사용자에게 알려서 이 예외를 정상적으로 처리할 책임이 있습니다.

일부 유형의 문서의 경우 제공된 동시성 수준이 필요하지 않을 수 있으며 마지막 우선 모델이 더 적합할 수 있습니다. 이러한 경우 문서를 편집하는 동안 이 기능을 나타내는 값으로 __etag 입력 -1. 앞에서 언급한 설정 서비스는 설정 및 기본 설정을 저장하기 위해 이 모델을 사용합니다.