以编程方式创建服务挂钩订阅

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

使用订阅 REST API,可以编程方式创建在 Azure DevOps 项目中发生特定事件时对外部/使用者服务执行操作的订阅。 例如,可以创建一个订阅,以便在生成失败时通知服务。

支持的事件:

  • 生成完毕
  • 推送的代码(适用于 Git 项目)
  • 创建或更新的拉取请求(适用于 Git 项目)
  • 签入的代码(TFVC 项目)
  • 创建、更新、删除、还原或注释的工作项

可以在订阅上配置筛选器,以控制触发操作的事件。 例如,可以根据生成状态筛选生成完毕事件。 有关一组完整的受支持事件和筛选器选项,请参阅事件参考

有关一组完整的受支持的使用者服务和操作,请参阅使用者参考

先决条件

若要创建订阅,需要以下数据:

创建请求

构造 HTTP POST 请求的正文,以基于项目 ID、事件、使用者和操作创建订阅。

请参阅以下示例请求,请求创建导致生成事件在生成WebSite.CI失败时 POST 到https://myservice/event的订阅。

Request

{
    "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"
    },
}

强烈建议使用安全 HTTPS URL 来保护 JSON 对象中的专用数据。

响应 请参阅对创建订阅的请求的以下响应:

{
    "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"
    }
}

如果订阅请求失败,则会收到 HTTP 响应代码 400,其中包含具有更多详细信息的消息。

事件发生时会发生什么情况?

事件发生时,将评估项目中所有已启用的订阅,并对所有匹配的订阅执行使用者操作。

资源版本(高级)

当 API 处于预览状态时,资源版本控制适用。 对于大多数方案,指定 1.0 为资源版本是最安全的路由。

发送到某些使用者的事件有效负载(如 Webhook、Azure 服务总线 和Azure 存储)包括主题资源的 JSON 表示形式(例如生成项或工作项)。 此资源的表示形式可以具有不同的窗体或版本。

可以通过订阅上的字段指定要发送到使用者服务 resourceVersion 的资源版本。 资源版本与 API 版本相同。 未指定资源版本意味着“最新发布”。 应始终指定资源版本,以确保一段时间内的事件有效负载一致。

常见问题

问:是否有服务可以手动订阅?

答: 是的。 有关可从项目管理页订阅的服务的详细信息,请参阅 概述

问:是否有可用于创建订阅的 C# 库?

答:否,但下面是帮助你入门的示例。

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; }
    }
}