Programmgesteuertes Erstellen eines Diensthakenabonnements

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

Mithilfe der Rest-APIs für Abonnements 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 Buildfehler auftritt.

Unterstützte Ereignisse:

  • Build abgeschlossen
  • Code gepusht (für Git-Projekte)
  • Pull Requests erstellt oder aktualisiert (für Git-Projekte)
  • Code eingecheckt (TFVC-Projekte)
  • Arbeitselement 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. Beispielsweise können Sie das Buildabschlussereignis auf der Grundlage des Buildstatus filtern. Den vollständigen Satz der unterstützten Ereignisse und Filteroptionen finden Sie in der Ereignisreferenz.

Den vollständigen Satz unterstützter Consumerdienste und -aktionen finden Sie in der Consumerreferenz.

Voraussetzungen

Zum Erstellen eines Abonnements sind die folgenden Daten erforderlich:

  • Die Projekt-ID. Verwenden Sie die Project REST-API , um die Projekt-ID abzurufen.
  • Ereignis-ID und -Einstellungen. Weitere Informationen finden Sie in der Ereignisreferenz.
  • Consumer- und Aktions-IDs und -Einstellungen. Siehe Verbraucherreferenz.

Erstellen der Anforderung

Erstellen Sie den Textkörper der HTTP POST-Anforderung, um das Abonnement basierend auf der Projekt-ID, dem Ereignis, dem Consumer und der Aktion zu erstellen.

Sehen Sie sich die folgende Beispielanforderung zum Erstellen eines Abonnements an, das dazu führt, dass ein Buildereignis POST angibt https://myservice/event , wenn der Build WebSite.CI fehlschlägt.

Anforderung

{
    "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": "74aeeed0-bf5d-48dc-893f-f862b80987e9",
    "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/hooks/subscriptions/74aeeed0-bf5d-48dc-893f-f862b80987e9",
    "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 Ressourcenversionsverwaltung gilt, wenn sich eine API in der Vorschau befindet. Für die meisten Szenarien ist die Angabe 1.0 der Ressourcenversion die sicherste Route.

Die an bestimmte Verbraucher gesendete Ereignisnutzlast, z. B. Webhooks, Azure Service Bus und Azure Storage, enthält eine JSON-Darstellung der Betreffressource (z. B. eine Build- oder Arbeitsaufgabe). Die Darstellung dieser Ressource kann unterschiedliche Formen oder Versionen aufweisen.

Sie können die Version der Ressource angeben, die Sie über das resourceVersion Feld im Abonnement an den Verbraucherdienst gesendet haben möchten. Die Ressourcenversion ist identisch mit der API-Version. Ohne Angabe einer Ressourcenversion bedeutet "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; }
    }
}