Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022
As extensões do Azure DevOps podem armazenar preferências do usuário e estruturas de dados complexas diretamente na infraestrutura fornecida pela Microsoft, o que garante que os dados do usuário sejam seguros e tenham backup, assim como outros dados de organização e projeto. Isso também significa que, para necessidades simples de armazenamento de dados, você, como provedor de extensão, não precisa configurar, gerenciar ou pagar por serviços de armazenamento de dados de terceiros.
Há dois métodos para se envolver com o serviço de armazenamento de dados: por meio de APIs REST ou por meio de um serviço cliente fornecido pela Microsoft, que faz parte do SDK do VSS. Aconselhamos os desenvolvedores de extensão a utilizar as APIs de serviço cliente fornecidas, pois elas oferecem um encapsulamento amigável das APIs REST.
Observação
Procurando APIs REST do Azure DevOps? Consulte a referência mais recente da API REST do Azure DevOps.
Para obter informações sobre bibliotecas de clientes .NET, consulte bibliotecas de clientes do .NET para Azure DevOps.
O que você pode armazenar
O serviço foi projetado para permitir que você armazene e gerencie dois tipos diferentes de dados:
- Configurações: configurações simples de chave-valor (como preferências do usuário)
- Documentos: coleções de objetos complexos semelhantes (documentos)
Uma coleção é como um contêiner indexado para documentos. Um documento é um blob JSON que pertence a uma coleção. Além de alguns nomes de propriedades reservadas, você controla e gerencia o esquema desses documentos.
Como você pode definir o escopo de dados
As configurações e as coleções de documentos podem ser definidas para:
- Coleção de projetos: compartilhada por todos os usuários da coleção de projetos à qual a extensão está instalada
- Usuário: um único usuário de uma coleção de projetos à qual a extensão está instalada
Armazenamento de configurações
Os dois métodos principais para gerenciar as configurações sãogetValue():setValue()
-
getValue()aceita uma chave de cadeia de caracteres (juntamente com outras opções, como escopo) e retorna um IPromise. O valor resolvido dessa promessa é o valor associado à chave fornecida. -
setValue()aceita uma chave de cadeia de caracteres, um valor e outras opções, como escopo, e retorna um IPromise. O valor resolvido dessa promessa é o valor atualizado da configuração.
Aqui está um exemplo de como definir um valor:
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
});
});
}
Aqui está um exemplo de como recuperar um valor de configuração:
// 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);
});
});
Se scopeType não for especificado, as configurações serão armazenadas no nível da coleção de projetos e poderão ser acessadas por todos os usuários nessa coleção de projetos usando a extensão.
Veja um exemplo de como definir um valor de configuração no nível da coleção do projeto:
// 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);
});
});
Armazenamento de dados (coleções de documentos)
Para lidar com dados mais complexos além dos pares chave-valor, você pode utilizar o conceito de documentos para executar operações CRUD nos dados da extensão. Um documento é um blob JSON, aprimorado com duas propriedades especiais: ID e __etag. Se forem cruciais para o modelo de dados de uma extensão, as IDs poderão ser definidas pelo usuário ou, se não forem especificadas, o sistema as gerará. Essas IDs devem ser exclusivas em uma coleção específica. Como uma coleção se refere a um escopo específico e uma instância de uma extensão, isso implica que a mesma ID de documento pode ser reutilizado em diferentes coleções.
As seguintes operações de documento estão disponíveis:
- Obter um documento
- Criar um documento
- Definir um documento (criar ou atualizar)
- Atualizar um documento
- Excluir um documento
Há também uma única operação que pode ser executada em uma coleção: Obter todos os documentos
Obter um documento por ID
Obter um documento de uma coleção usando seu identificador é simples, como o exemplo a seguir:
// 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);
});
});
Esta operação tenta buscar um documento com a ID "MyDocumentId" da coleção "MyCollection". Na ausência de um escopo fornecido, o serviço usa o padrão de usar a coleção com escopo para toda a instância dessa extensão. Se essa coleção ou um documento com a ID especificada não existir, um erro 404 será retornado, que a extensão deve manipular. O documento retornado é um objeto JSON que inclui todas as suas propriedades, juntamente com a ID especial e __etag as propriedades utilizadas pelo serviço de armazenamento de dados.
// 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);
});
});
Essa chamada tenta recuperar um documento com a ID "MyDocumentId", da coleção "MyCollection". Como nenhum escopo é fornecido, a coleção que o serviço usa tem como escopo o padrão de toda a instância dessa extensão. Se essa coleção não existir ou um documento com essa ID não existir, um 404 será retornado, que a extensão deve manipular. O documento retornado é um objeto JSON que contém todas as suas próprias propriedades, além da ID especial e __etag das propriedades usadas pelo serviço de armazenamento de dados.
Criar um documento
Para criar um novo documento, execute uma chamada como o seguinte exemplo:
// 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);
});
});
Se a coleção com o nome e o escopo fornecidos, ainda não existir, ela será criada dinamicamente antes que o documento em si seja criado.
Se o documento fornecido contiver uma id propriedade, esse valor será usado como a ID exclusiva do documento. Observe que o fornecido id deve ser limitado a 50 caracteres. Se esse campo não existir, um GUID será gerado pelo serviço e incluído no documento retornado quando a promessa for resolvida.
Se outro documento na coleção já existir com a mesma ID fornecida no documento, a operação falhará. Se o comportamento desejado for criar um novo documento se a ID não existir, mas modificar o documento existente se ele existir, o setDocument() método deverá ser usado.
Definir um documento (atualizar ou criar)
A setDocument() função executa uma operação "upsert" – ela modifica um documento existente se sua ID estiver presente e corresponder a um documento na coleção. Se a ID estiver ausente ou não corresponder a nenhum documento na coleção, um novo documento será adicionado à coleção.
// 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);
});
});
Atualizar um documento
A updateDocument função requer que o documento que está sendo alterado já resida na coleção. Uma exceção será gerada se nenhuma ID for fornecida ou se a ID fornecida não corresponder a nenhum documento na coleção.
Veja um exemplo de como a atualização é usada:
// 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);
});
});
});
Excluir um documento
Essa função exclui o documento com a ID fornecida da coleção fornecida. Se a coleção não existir ou o documento não existir, um 404 será retornado.
Aqui está um uso de exemplo:
// 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");
});
});
Obter todos os documentos em uma coleção
O exemplo a seguir recupera todos os documentos da coleção "MyCollection" usando o serviço de dados e registra o número de documentos no console:
// 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.");
});
});
Essa chamada recupera todos os documentos em uma coleção com escopo, com um limite de 100.000 documentos. Se a coleção for inexistente, ela retornará um erro 404.
Avançado
Como as configurações são armazenadas
Essa chamada encapsula o setDocument método cliente, fornecendo-o com várias partes de dados. Conforme indicado anteriormente, as configurações são salvas internamente como documentos. Portanto, um documento básico é gerado dinamicamente, em que a ID do documento é a chave fornecida no setValue() método. O documento tem mais duas propriedades. A value propriedade contém o valor passado para o método e a revision propriedade é definida como -1. Embora a revision propriedade seja elaborada mais na seção "Trabalhando com documentos", no contexto das configurações, a revision configuração -1 no documento significa que não estamos preocupados com o controle de versão deste documento de configurações.
Como as configurações são armazenadas como documentos, precisamos fornecer um nome de coleção, indicando onde armazenar o documento. Para manter as coisas simples, ao trabalhar com os setValue()/getValue() métodos, o nome da coleção é sempre o nome $settingsespecial. A chamada anterior emite uma solicitação PUT no seguinte ponto de extremidade:
GET _apis/ExtensionManagement/InstalledExtensions/{publisherName}/{extensionName}/Data/Scopes/User/Me/Collections/%24settings/Documents
O conteúdo da solicitação é semelhante ao exemplo a seguir:
{
"id": "myKey",
"__etag": -1,
"value": "myValue"
}
REST APIs
Supondo que esse snippet seja executado depois que o valor for definido, você deverá ver uma mensagem de alerta contendo o texto "O valor é myValue". O método getValue é novamente um wrapper em torno das APIs REST, emitindo uma solicitação GET para o seguinte ponto de extremidade:
GET _apis/ExtensionManagement/InstalledExtensions/{publisherName}/{extensionName}/Data/Scopes/User/Me/Collections/%24settings/Documents/myKey
etags
O __etag campo é usado pelo Serviço de Armazenamento de Dados para gerenciamento de simultaneidade de documentos. Antes que uma atualização seja salva, o serviço verifica se o __etag documento armazenado atualmente corresponde ao __etag do documento atualizado. Se corresponderem, o __etag documento será incrementado e o documento atualizado será retornado ao chamador. Se eles não corresponderem, isso indicará que o documento a ser atualizado está desatualizado e uma exceção será gerada. O gravador de extensão é responsável por lidar com essa exceção normalmente, recuperando o mais recente __etag do documento, mesclando as alterações e repetindo a atualização ou notificando o usuário.
Para alguns tipos de documentos, o nível de simultaneidade fornecido pode não ser necessário e um modelo de última geração pode ser mais adequado. Nesses casos, ao editar o documento, a entrada -1 como o __etag valor para significar essa funcionalidade. O serviço de configurações mencionado anteriormente emprega esse modelo para armazenar configurações e preferências.