Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022
Les extensions Azure DevOps peuvent stocker les préférences utilisateur et les structures de données complexes directement sur l’infrastructure fournie par Microsoft, ce qui garantit que les données de votre utilisateur sont sécurisées et sauvegardées comme d’autres données d’organisation et de projet. Cela signifie également que pour les besoins de stockage de données simples, vous, en tant que fournisseur d’extension, ne sont pas tenus de configurer, de gérer ou de payer pour les services de stockage de données tiers.
Il existe deux méthodes permettant d’interagir avec le service de stockage de données : via des API REST ou via un service client fourni par Microsoft, qui fait partie du Kit de développement logiciel (SDK) VSS. Nous conseillons aux développeurs d’extensions d’utiliser les API de service client fournies, car ils offrent une encapsulation conviviale des API REST.
Note
Vous recherchez des API REST Azure DevOps ? Consultez la dernière référence de l’API REST Azure DevOps.
Pour plus d’informations sur les bibliothèques clientes .NET, consultez les bibliothèques clientes .NET pour Azure DevOps.
Ce que vous pouvez stocker
Le service est conçu pour vous permettre de stocker et de gérer deux types de données différents :
- Paramètres : paramètres de clé-valeur simples (comme les préférences utilisateur)
- Documents : collections d’objets complexes similaires (documents)
Une collection est un conteneur indexé pour les documents. Un document est un objet blob JSON qui appartient à une collection. À part quelques noms de propriétés réservées, vous contrôlez et gérez le schéma de ces documents.
Comment étendre les données
Les paramètres et les collections de documents peuvent être limités à l’une des options suivantes :
- Collection de projets : partagée par tous les utilisateurs de la collection de projets sur laquelle l’extension est installée
- Utilisateur : un seul utilisateur d’une collection de projets sur laquelle l’extension est installée
Stockage des paramètres
Les deux méthodes principales de gestion des paramètres sont getValue() les setValue()suivantes :
-
getValue()accepte une clé de chaîne (ainsi que d’autres options telles que l’étendue) et retourne un IPromise. La valeur résolue de cette promesse est la valeur associée à la clé fournie. -
setValue()accepte une clé de chaîne, une valeur et d’autres options telles que l’étendue et retourne un IPromise. La valeur résolue de cette promesse est la valeur mise à jour du paramètre.
Voici un exemple de définition d’une valeur :
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
});
});
}
Voici un exemple de récupération d’une valeur de paramètre :
// 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);
});
});
S’il scopeType n’est pas spécifié, les paramètres sont stockés au niveau de la collection de projets et sont accessibles à tous les utilisateurs de cette collection de projets à l’aide de l’extension.
Voici un exemple de définition d’une valeur de paramètre au niveau de la collection de projets :
// 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);
});
});
Stockage de données (collections de documents)
Pour gérer des données plus complexes au-delà des paires clé-valeur, vous pouvez utiliser le concept de documents pour exécuter des opérations CRUD sur les données de votre extension. Un document est un objet blob JSON, amélioré avec deux propriétés spéciales : ID et __etag. S’ils sont essentiels au modèle de données d’une extension, les ID peuvent être définis par l’utilisateur ou, s’ils ne sont pas spécifiés, le système les génère. Ces ID doivent être uniques dans une collection spécifique. Étant donné qu’une collection fait référence à une étendue et une instance particulières d’une extension, elle implique que le même ID de document peut être réutilisé dans différentes collections.
Les opérations de document suivantes sont disponibles :
- Obtenir un document
- Créer un document
- Définir un document (créer ou mettre à jour)
- Mettre à jour un document
- Supprimer un document
Il existe également une seule opération qui peut être effectuée sur une collection : obtenir tous les documents
Obtenir un document par ID
L’obtention d’un document à partir d’une collection à l’aide de son identificateur est simple, comme dans l’exemple suivant :
// 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);
});
});
Cette opération tente d’extraire un document avec l’ID « MyDocumentId » de la collection « MyCollection ». En l’absence d’une étendue fournie, le service utilise par défaut la collection étendue à l’instance entière de cette extension. Si cette collection ou un document avec l’ID spécifié n’existe pas, une erreur 404 est retournée, que l’extension doit gérer. Le document retourné est un objet JSON qui inclut toutes ses propriétés, ainsi que l’ID spécial et __etag les propriétés utilisées par le service de stockage de données.
// 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);
});
});
Cet appel tente de récupérer un document avec l’ID « MyDocumentId », à partir de la collection « MyCollection ». Étant donné qu’aucune étendue n’est fournie, la collection utilisée par le service est étendue à la valeur par défaut de l’instance entière de cette extension. Si cette collection n’existe pas ou qu’un document avec cet ID n’existe pas, un 404 est retourné, que l’extension doit gérer. Le document retourné est un objet JSON contenant toutes ses propres propriétés, en plus de l’ID spécial et __etag des propriétés utilisées par le service de stockage de données.
Créer un document
Pour créer un document, effectuez un appel comme dans l’exemple suivant :
// 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);
});
});
Si la collection portant le nom et l’étendue fournis n’existe pas encore, elle est créée dynamiquement avant la création du document lui-même.
Si le document fourni contient une id propriété, cette valeur est utilisée comme ID unique pour le document. Notez que les caractères fournis id doivent être limités à 50 caractères. Si ce champ n’existe pas, un GUID est généré par le service et inclus dans le document retourné lorsque la promesse est résolue.
Si un autre document de la collection existe déjà avec le même ID que celui fourni sur le document, l’opération échoue. Si le comportement souhaité est créé un document si l’ID n’existe pas, mais modifiez le document existant le cas échéant, la setDocument() méthode doit être utilisée.
Définir un document (mettre à jour ou créer)
La setDocument() fonction effectue une opération « upsert » : elle modifie un document existant si son ID est présent et correspond à un document de la collection. Si l’ID est absent ou ne correspond à aucun document de la collection, un nouveau document est ajouté à la collection.
// 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);
});
});
Mettre à jour un document
La updateDocument fonction exige que le document en cours de modification réside déjà dans la collection. Une exception est levée si aucun ID n’est fourni ou si l’ID fourni ne correspond à aucun document de la collection.
Voici un exemple de la façon dont la mise à jour est utilisée :
// 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);
});
});
});
Supprimer un document
Cette fonction supprime le document avec l’ID fourni de la collection fournie. Si la collection n’existe pas ou si le document n’existe pas, un 404 est retourné.
Voici un exemple d’utilisation :
// 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");
});
});
Obtenir tous les documents d’une collection
L’exemple suivant récupère tous les documents de la collection « MyCollection » à l’aide du service de données, puis enregistre le nombre de documents dans la 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.");
});
});
Cet appel récupère tous les documents d’une collection délimitée, avec une limite de 100 000 documents. Si la collection n’existe pas, elle renvoie une erreur 404.
Advanced
Comment les paramètres sont stockés
Cet appel encapsule la setDocument méthode cliente, en lui fournissant plusieurs éléments de données. Comme indiqué précédemment, les paramètres sont enregistrés en interne en tant que documents. Par conséquent, un document de base est généré dynamiquement, où l’ID du document est la clé donnée dans la setValue() méthode. Le document a deux propriétés supplémentaires. La value propriété contient la valeur passée à la méthode, et la revision propriété est définie sur -1. Bien que la propriété soit développée plus loin dans la section « Utilisation des documents », dans le contexte des paramètres, la revision définition revision-1 dans le document signifie que nous ne sommes pas préoccupés par le contrôle de version de ce document de paramètres.
Étant donné que les paramètres sont stockés en tant que documents, nous devons fournir un nom de collection, indiquant où stocker le document. Pour simplifier les choses, lorsque vous travaillez avec les setValue()/getValue() méthodes, le nom de la collection est toujours le nom $settingsspécial. L’appel précédent émet une demande PUT au point de terminaison suivant :
GET _apis/ExtensionManagement/InstalledExtensions/{publisherName}/{extensionName}/Data/Scopes/User/Me/Collections/%24settings/Documents
La charge utile de la requête est semblable à l’exemple suivant :
{
"id": "myKey",
"__etag": -1,
"value": "myValue"
}
API REST
En supposant que cet extrait de code est exécuté une fois la valeur définie, vous devez voir un message d’alerte contenant le texte « La valeur est myValue ». La méthode getValue est à nouveau un wrapper autour des API REST, en émettant une requête GET au point de terminaison suivant :
GET _apis/ExtensionManagement/InstalledExtensions/{publisherName}/{extensionName}/Data/Scopes/User/Me/Collections/%24settings/Documents/myKey
etags
Le __etag champ est utilisé par le service de stockage de données pour la gestion de la concurrence des documents. Avant l’enregistrement d’une mise à jour, le service vérifie que le __etag document actuellement stocké correspond au __etag document mis à jour. S’ils correspondent, le __etag document est incrémenté et le document mis à jour est retourné à l’appelant. S’ils ne correspondent pas, cela indique que le document à mettre à jour est obsolète et qu’une exception est levée. L’enregistreur d’extensions est chargé de gérer cette exception correctement, soit en récupérant la dernière version __etag du document, en fusionnant les modifications et en retenant la mise à jour, soit en informant l’utilisateur.
Pour certains types de documents, le niveau d’accès concurrentiel fourni peut ne pas être nécessaire, et un modèle dernier-in-wins peut être plus approprié. Dans ce cas, lors de la modification du document, l’entrée -1 comme __etag valeur pour signer cette fonctionnalité. Le service de paramètres mentionné précédemment utilise ce modèle pour stocker les paramètres et les préférences.