Freigeben über


Programmatische Erstellung eines Service-Hook-Abonnements

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

Sie können ein Abonnement verwenden, um eine Aktion für einen externen oder Consumerdienst auszuführen, wenn ein bestimmtes Ereignis in einem Azure DevOps-Projekt auftritt. Beispielsweise kann ein Abonnement Ihren Dienst benachrichtigen, wenn ein Build fehlschlägt.

Um ein Abonnement programmgesteuert zu erstellen, können Sie die Rest-APIs für Abonnements verwenden. Dieser Artikel enthält eine Beispielanforderung und einen Beispielcode zum Erstellen eines Abonnements.

Voraussetzungen

Kategorie Anforderungen
Projektzugang Projektmitglied.
Daten - Projekt-ID. Verwenden Sie die Project REST-API, um die Projekt-ID abzurufen.
- Ereignis-ID und -Einstellungen. Siehe Service-Hook-Ereignisse.
– Verbraucher- und Aktions-IDs und -Einstellungen. Siehe Service Hook Consumer.

Unterstützte Ereignisse

Azure DevOps bietet Unterstützung für zahlreiche Triggerereignisse. Beispiele hierfür sind die folgenden Ereignisse:

  • Erstellung abgeschlossen
  • Code gepusht (für Git-Projekte)
  • Pullanforderung erstellt oder aktualisiert (für Git-Projekte)
  • Code eingecheckt (für Team Foundation Version Control-Projekte)
  • Arbeitsaufgabe erstellt, aktualisiert, gelöscht, wiederhergestellt oder kommentiert

Um zu steuern, welche Ereignisse eine Aktion auslösen, können Sie Filter für Ihre Abonnements konfigurieren. Sie können z. B. das abgeschlossene Build-Ereignis basierend auf dem Build-Status filtern.

  • Einen vollständigen Satz unterstützter Ereignisse und Filteroptionen finden Sie unter Service hook-Ereignisse.
  • Einen vollständigen Satz unterstützter Verbraucherdienste und -aktionen finden Sie unter Service Hook Consumer.

Anforderung erstellen

Wenn Sie ein Abonnement erstellen, verwenden Sie den Text einer HTTP POST-Anforderung, um die Projekt-ID, das Ereignis, die Verbraucher, die Aktion und die zugehörigen Einstellungen anzugeben.

Sie können die folgende Anforderung verwenden, um ein Abonnement für ein abgeschlossenes Buildereignis zu erstellen. Wenn der WebSite.CI Build in diesem Beispiel fehlschlägt, sendet das Abonnement eine POST-Anforderung an https://myservice/event.

Anfordern

{
    "publisherId": "tfs",
    "eventType": "build.complete",
    "resourceVersion": "1.0",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "projectId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
    },
    "consumerInputs": {
        "url": " https://myservice/event"
    },
}

Es wird dringend empfohlen, sichere HTTPS-URLs für die Sicherheit der privaten Daten im JSON-Objekt zu verwenden.

Antwort

Die Anforderung zum Erstellen des Abonnements generiert eine Antwort, die dem folgenden ähnelt:

{
    "id": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
    "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/hooks/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
    "publisherId": "tfs",
    "eventType": "build.complete",
    "resourceVersion": "1.0",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "createdBy": {
        "id": "22cc22cc-dd33-ee44-ff55-66aa66aa66aa"
    },
    "createdDate": "2014-03-28T16:10:06.523Z",
    "modifiedBy": {
        "id": "22cc22cc-dd33-ee44-ff55-66aa66aa66aa"
    },
    "modifiedDate": "2014-04-25T18:15:26.053Z",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "hostId": "d3d3d3d3-eeee-ffff-aaaa-b4b4b4b4b4b4",
        "projectId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
        "tfsSubscriptionId": "ffff5f5f-aa6a-bb7b-cc8c-dddddd9d9d9d"
    },
    "consumerInputs": {
        "url": "http://myservice/event"
    }
}

Wenn die Abonnementanforderung fehlschlägt, erhalten Sie einen HTTP-Antwortcode von 400 mit einer Nachricht, die weitere Details enthält.

Was geschieht, wenn das Ereignis eintritt?

Wenn ein Ereignis eintritt, werden alle aktivierten Abonnements im Projekt ausgewertet. Anschließend wird die Verbraucheraktion für alle übereinstimmenden Abonnements ausgeführt.

Ressourcenversionen (erweitert)

Die Ressourcen-Versionierung ist anwendbar, wenn sich eine API in der Vorschau befindet. Für die meisten Szenarien ist die Angabe von 1.0 als die Ressourcenversion der sicherste Weg.

Die an bestimmte Verbraucher gesendete Ereignisnutzlast enthält eine JSON-Darstellung einer Subjektressource. Beispielsweise enthält die Nutzlast, die an Webhooks, Azure Service Bus und Azure Storage gesendet wird, Informationen zu einem Build oder Arbeitselement. Die Darstellung dieser Ressource kann verschiedene Formulare oder Versionen aufweisen.

Sie können die Version der Ressource angeben, die Sie über das resourceVersion Feld im Abonnement an den Verbraucherdienst senden möchten.

Die Ressourcenversion ist mit der API-Versionidentisch. Wenn Sie keine Ressourcenversion angeben, wird die neueste Version latest releasedverwendet. Um eine konsistente Ereignisnutzlast im Laufe der Zeit sicherzustellen, geben Sie immer eine Ressourcenversion an.

Häufig gestellte Fragen

F: Gibt es Dienste, die ich manuell abonnieren kann?

A: Ja. Weitere Informationen zu den Diensten, die Sie von einer Projektverwaltungsseite aus abonnieren können, finden Sie unter Integration mit Service Hooks.

F: Gibt es C#-Bibliotheken, die ich zum Erstellen von Abonnements verwenden kann?

A: Nein, aber hier ist ein Beispiel, das Ihnen bei den ersten Schritten hilft. Für die Authentifizierung bei Azure DevOps verwendet der folgende Code ein persönliches Zugriffstoken (PAT), das in Azure Key Vault gespeichert ist. Verwenden Sie in einer Produktionsumgebung eine sicherere Authentifizierungsmethode. Weitere Informationen finden Sie unter Auswählen des richtigen Authentifizierungsmechanismus.

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.ServiceHooks.WebApi;
using Microsoft.VisualStudio.Services.WebApi;

namespace CreateServiceHookSubscription
{
    internal class Program
    {
        // Create a service hook subscription to send a message to an Azure Service Bus queue when code is pushed to a Git repository.

        static async Task Main(string[] args)
        {
            // Get the secrets from the key vault.
            string keyVaultURI = "https://<key-vault-name>.vault.azure.net/";
            var secretClient = new SecretClient(new Uri(keyVaultURI), new DefaultAzureCredential());
            string personalAccessTokenSecretName = "<personal-access-token-secret-name>";
            string serviceBusConnectionStringSecretName = "<Service-Bus-connection-string-secret-name>";
            KeyVaultSecret personalAccessTokenSecret = await secretClient.GetSecretAsync(personalAccessTokenSecretName);
            KeyVaultSecret serviceBusConnectionStringSecret = await secretClient.GetSecretAsync(serviceBusConnectionStringSecretName);

            // Set up the connection parameters for Azure DevOps.
            var azureDevOpsOrganizationURL = new Uri("https://dev.azure.com/<Azure-DevOps-organization-name>/");
            string azureDevOpsTeamProjectID = "<Azure-DevOps-team-project-ID>";
            string azureDevOpsPersonalAccessToken = personalAccessTokenSecret.Value;

            // Set up the event parameters.
            string eventPublisherID = "tfs";
            string eventID = "git.push";
            string eventDescription = "Any stage in any release";
            string resourceVersion = "1.0";

            // Set up the consumer parameters.
            string consumerID = "azureServiceBus";
            string consumerActionID = "serviceBusQueueSend";
            string serviceBusNamespace = "<Service-Bus-namespace>";
            string serviceBusQueueName = "<Service-Bus-queue-name>";
            string consumerActionDescription = $"Send a message to the Service Bus {serviceBusQueueName} queue in the {serviceBusNamespace} namespace.";
            string serviceBusConnectionString = serviceBusConnectionStringSecret.Value;

            // Configure the subscription.
            var subscription = new Subscription()
            {
                PublisherId = eventPublisherID,
                PublisherInputs = new Dictionary<string, string>
                {
                    ["projectId"] = azureDevOpsTeamProjectID
                },
                EventType = eventID,
                EventDescription = eventDescription,
                ResourceVersion = resourceVersion,
                ActionDescription = consumerActionDescription,
                ConsumerActionId = consumerActionID,
                ConsumerId = consumerID,
                ConsumerInputs = new Dictionary<string, string>
                {
                    ["connectionString"] = serviceBusConnectionString,
                    ["queueName"] = serviceBusQueueName
                }
            };

            // Connect to the Azure DevOps organization and get a service hook client.
            var azureDevOpsCredentials = new VssBasicCredential(azureDevOpsPersonalAccessToken, string.Empty);
            var azureDevOpsConnection = new VssConnection(azureDevOpsOrganizationURL, azureDevOpsCredentials);
            var serviceHookClient = azureDevOpsConnection.GetClient<ServiceHooksPublisherHttpClient>();

            // Create the subscription.
            var createdSubscription = await serviceHookClient.CreateSubscriptionAsync(subscription);
            Console.WriteLine($"A subscription was created that has ID {createdSubscription.Id}.");
        }
    }
}