Teilen über


Programmatische Erstellung eines Service-Hook-Abonnements

Azure DevOps Services | Azure DevOps Server 2022 – Azure DevOps Server 2019

Mithilfe der Abonnements-REST-APIs können Sie programmgesteuert ein Abonnement erstellen, das eine Aktion für einen externen/Consumerdienst ausführt, wenn ein bestimmtes Ereignis in einem Azure DevOps-Projekt auftritt. Sie können beispielsweise ein Abonnement erstellen, um Ihren Dienst zu benachrichtigen, wenn ein Build fehlschlägt.

Unterstützte Ereignisse:

  • Erstellung abgeschlossen
  • Code gepusht (für Git-Projekte)
  • Erstellen oder Aktualisieren der Pull-Anforderung (für Git-Projekte)
  • Code eingecheckt (TFVC-Projekte)
  • Arbeitsaufgabe erstellt, aktualisiert, gelöscht, wiederhergestellt oder kommentiert

Sie können Filter für Ihre Abonnements konfigurieren, um zu steuern, welche Ereignisse eine Aktion auslösen. 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 in der Ereignisreferenz.

Eine vollständige Reihe unterstützter Verbraucherdienste und -aktionen finden Sie in der Verbraucherreferenz.

Voraussetzungen

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

Erstellen der Anforderung

Erstellen Sie den Inhalt der HTTP POST-Anforderung, um das Abonnement basierend auf der Projekt-ID, dem Ereignis, dem Verbraucher und der Aktion zu erstellen.

Sehen Sie sich die folgende Beispielanfrage an, um ein Abonnement zu erstellen, das bewirkt, dass ein Build-Ereignis an https://myservice/event gesendet wird, wenn der Build WebSite.CI fehlschlägt.

Anfordern

{
    "publisherId": "tfs",
    "eventType": "build.complete",
    "resourceVersion": "1.0",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "projectId": "56479caf-1eeb-4bca-86ab-aaa6f29399d9",
    },
    "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 Sehen Sie sich die folgende Antwort auf die Anforderung zum Erstellen des Abonnements an:

{
    "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": "00ca946b-2fe9-4f2a-ae2f-40d5c48001bc"
    },
    "createdDate": "2014-03-28T16:10:06.523Z",
    "modifiedBy": {
        "id": "1c4978ae-7cc9-4efa-8649-5547304a8438"
    },
    "modifiedDate": "2014-04-25T18:15:26.053Z",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "WebSite.CI",
        "hostId": "17f27955-99bb-4861-9550-f2c669d64fc9",
        "projectId": "56479caf-1eeb-4bca-86ab-aaa6f29399d9",
        "tfsSubscriptionId": "29cde8b4-f37e-4ef9-a6d4-d57d526d82cc"
    },
    "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 auftritt, werden alle aktivierten Abonnements im Projekt ausgewertet, und die Verbraucheraktion wird 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 Consumer wie Webhooks, Azure Service Bus und Azure Storage gesendete Ereignisnutzlast enthält eine JSON-Darstellung der Objektressource (z. B. ein Build- oder Arbeitselement). Die Darstellung dieser Ressource kann unterschiedliche Formen oder Versionen aufweisen.

Sie können die Version der Ressource angeben, die Sie über das Feld resourceVersion im Abonnement an den Verbraucherdienst gesendet haben möchten. Die Ressourcenversion ist mit der API-Versionidentisch. Ohne Angabe einer Ressourcenversion heißt es "neueste Veröffentlichung". Sie sollten immer eine Ressourcenversion angeben, die eine konsistente Ereignisnutzlast im Laufe der Zeit sicherstellt.

Häufig gestellte Fragen

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

A: Ja. Weitere Informationen zu den Diensten, die Sie von der Verwaltungsseite für ein Projekt abonnieren können, finden Sie in der Übersicht.

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.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Mvc;

namespace Microsoft.Samples.VisualStudioOnline
{
    public class ServiceHookEventController : Controller
    {

        // POST: /ServiceHookEvent/workitemcreated
        [HttpPost]
        public HttpResponseMessage WorkItemCreated(Content workItemEvent)
        {
            //Grabbing the title for the new workitem
            var value = RetrieveFieldValue("System.field", workItemEvent.Resource.Fields);

            //Acknowledge event receipt
            return new HttpResponseMessage(HttpStatusCode.OK);
        }

        /// <summary>
        /// Gets the value for a specified work item field.
        /// </summary>
        /// <param name="key">Key used to retrieve matching value</param>
        /// <param name="fields">List of fields for a work item</param>
        /// <returns></returns>
        public String RetrieveFieldValue(String key, IList<FieldInfo> fields)
        {
            if (String.IsNullOrEmpty(key))
                return String.Empty;

            var result = fields.Single(s => s.Field.RefName == key);

            return result.Value;
        }

	}

    public class Content
    {
        public String SubscriptionId { get; set; }

        public int NotificationId { get; set; }

        public String EventType { get; set; }

        public WorkItemResource Resource { get; set; }

    }

    public class WorkItemResource
    {
        public String UpdatesUrl { get; set; }

        public IList<FieldInfo> Fields { get; set;}

        public int Id { get; set; }

        public int Rev { get; set; }

        public String Url { get; set; }

        public String WebUrl { get; set; }
    }

    public class FieldInfo
    {
        public FieldDetailedInfo Field { get; set; }

        public String Value { get; set; }

    }

    public class FieldDetailedInfo
    {
        public int Id { get; set; }

        public String Name { get; set; }

        public String RefName { get; set; }
    }
}