使用 Webhook 将 Microsoft Dataverse 服务器事件发送到外部 Web 应用程序。 本文介绍 Dataverse 发送的请求数据,以及 Webhook 如何帮助你为服务器事件生成外部处理程序。
通过使用 Webhook,开发人员和 ISV 可以将 Dataverse 数据与托管在外部服务上的自己的自定义代码集成。 通过使用 Webhook 模型,您可以使用身份验证标头或查询字符串参数键来保护终结点。 此方法比当前可用于 Azure 服务总线集成的 SAS 身份验证模型更简单。
在 Webhook 模型与 Azure 服务总线集成之间做出决定时,请记住以下几点:
- Azure 服务总线适用于大规模处理,如果 Dataverse 正在推送许多事件,则提供完整的队列机制。
- Webhook 仅调整至托管 Web 服务能够处理消息的水平。
- Webhooks 启用同步和异步操作。 Azure 服务总线仅允许异步步骤。
- Webhook 使用 JSON 有效负载发送 POST 请求,可以由托管在任何地方的任何编程语言或 Web 应用程序使用。
- 可以从插件或自定义工作流活动调用 Webhook 和 Azure 服务总线。
开始
使用Webhook涉及三个部分:
- 创建或配置服务以使用 Webhook 请求。
- 在 Dataverse 服务上注册 Webhook 的步骤。
- 从插件或自定义工作流活动调用 webhook。
首先注册一个用于测试的 WebHook
若要了解如何创建和配置服务以使用 Dataverse 中的 WebHook 请求,请首先了解如何注册 WebHook。 有关详细信息,请参阅 注册 WebHook。
注册示例 WebHook 后,使用请求日志记录站点检查传递的上下文数据。 有关详细信息,请参阅 使用请求日志记录站点测试 WebHook 注册。
小窍门
完成注册测试 WebHook 的步骤,并检查通过的上下文数据,这使本主题中的其余信息更易于理解。 完成这些步骤并返回到本主题。
创建或配置服务以处理 WebHook 请求
Webhook 只是一种模式,它们可以通过各种技术来实现。 无需使用框架、平台或编程语言。 使用您所掌握的技能和知识来提供适当的解决方案。
Azure Functions 提供了使用 Webhook 交付解决方案的绝佳方法,但这不是一项要求。 本部分不提供特定解决方案的指导。 而是描述 Dataverse 传递给您的服务的数据,使您的服务能够增加其价值。
如 测试 WebHook 注册请求日志记录站点中所述,可以注册测试 WebHook 步骤,并使用请求日志记录站点捕获应用程序可以处理的特定数据类型。
传递到服务的数据
请求包括三种类型的数据:查询字符串、标头数据和请求正文。
查询字符串
作为查询字符串传递的唯一数据是身份验证值,如果您将 WebHook 配置为使用 WebhookKey 或 HttpQueryString 选项,如 身份验证选项 中所述。
标头数据
如果选择 HttpHeader 身份验证选项,请使用服务所需的密钥/值对。
预计您的服务将收到以下数据:
| 键 | 值描述 |
|---|---|
x-ms-dynamics-organization |
发送请求的环境的域名 |
x-ms-dynamics-entity-name |
在执行上下文数据中传递的表的逻辑名称。 |
x-ms-dynamics-request-name |
注册 WebHook 步骤的事件名称。 |
x-ms-correlation-request-id |
用于跟踪任何类型的扩展的唯一标识符。 平台使用此属性进行无限循环防护。 在大多数情况下,可以忽略此属性。 使用技术支持时,此值可用于查询遥测,以了解整个操作期间发生的情况。 |
x-ms-dynamics-msg-size-exceeded |
仅当 HTTP 有效负载大小超过 256 KB 时发送。 |
请求正文
正文包含一个字符串,表示类实例的 RemoteExecutionContext JSON 值。 这些数据同样被传递到 Azure 服务总线 (Service Bus) 集成。
您创建的服务必须分析此数据,以提取服务的相关信息项来提供服务功能。 选择分析此数据的方式取决于所使用的技术和偏好。
以下示例展示了注册具有以下属性的步骤传递的序列化 JSON 数据:
| 财产 | Description |
|---|---|
| Message | 更新 |
| 主要实体 | 联系人 |
| 辅助实体 | 没有 |
| 筛选属性 | firstname,lastname |
| 在用户的上下文中运行 | 呼叫用户 |
| 执行顺序 | 1 |
| 执行的事件管道阶段 | PostOperation |
| 执行模式 | 异步 |
{
"BusinessUnitId": "e2b9dd85-e89e-e711-8122-000d3aa2331c",
"CorrelationId": "aaaa0000-bb11-2222-33cc-444444dddddd",
"Depth": 1,
"InitiatingUserId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
"InputParameters": [{
"key": "Target",
"value": {
"__type": "Entity:http:\/\/schemas.microsoft.com\/xrm\/2011\/Contracts",
"Attributes": [{
"key": "firstname",
"value": "James"
}, {
"key": "contactid",
"value": "6d81597f-0f9f-e711-8122-000d3aa2331c"
}, {
"key": "fullname",
"value": "James Glynn (sample)"
}, {
"key": "yomifullname",
"value": "James Glynn (sample)"
}, {
"key": "modifiedon",
"value": "\/Date(1506384247000)\/"
}, {
"key": "modifiedby",
"value": {
"__type": "EntityReference:http:\/\/schemas.microsoft.com\/xrm\/2011\/Contracts",
"Id": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
"KeyAttributes": [],
"LogicalName": "systemuser",
"Name": null,
"RowVersion": null
}
}, {
"key": "modifiedonbehalfby",
"value": null
}],
"EntityState": null,
"FormattedValues": [],
"Id": "6d81597f-0f9f-e711-8122-000d3aa2331c",
"KeyAttributes": [],
"LogicalName": "contact",
"RelatedEntities": [],
"RowVersion": null
}
}],
"IsExecutingOffline": false,
"IsInTransaction": false,
"IsOfflinePlayback": false,
"IsolationMode": 1,
"MessageName": "Update",
"Mode": 1,
"OperationCreatedOn": "\/Date(1506409448000-0700)\/",
"OperationId": "4af10637-4ea2-e711-8122-000d3aa2331c",
"OrganizationId": "00aa00aa-bb11-cc22-dd33-44ee44ee44ee",
"OrganizationName": "OrgName",
"OutputParameters": [],
"OwningExtension": {
"Id": "75417616-4ea2-e711-8122-000d3aa2331c",
"KeyAttributes": [],
"LogicalName": "sdkmessageprocessingstep",
"Name": null,
"RowVersion": null
},
"ParentContext": {
"BusinessUnitId": "e2b9dd85-e89e-e711-8122-000d3aa2331c",
"CorrelationId": "aaaa0000-bb11-2222-33cc-444444dddddd",
"Depth": 1,
"InitiatingUserId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
"InputParameters": [{
"key": "Target",
"value": {
"__type": "Entity:http:\/\/schemas.microsoft.com\/xrm\/2011\/Contracts",
"Attributes": [{
"key": "firstname",
"value": "James"
}, {
"key": "contactid",
"value": "6d81597f-0f9f-e711-8122-000d3aa2331c"
}],
"EntityState": null,
"FormattedValues": [],
"Id": "6d81597f-0f9f-e711-8122-000d3aa2331c",
"KeyAttributes": [],
"LogicalName": "contact",
"RelatedEntities": [],
"RowVersion": null
}
}, {
"key": "SuppressDuplicateDetection",
"value": false
}],
"IsExecutingOffline": false,
"IsInTransaction": false,
"IsOfflinePlayback": false,
"IsolationMode": 1,
"MessageName": "Update",
"Mode": 1,
"OperationCreatedOn": "\/Date(1506409448000-0700)\/",
"OperationId": "4af10637-4ea2-e711-8122-000d3aa2331c",
"OrganizationId": "00aa00aa-bb11-cc22-dd33-44ee44ee44ee",
"OrganizationName": "OneFarm",
"OutputParameters": [],
"OwningExtension": {
"Id": "75417616-4ea2-e711-8122-000d3aa2331c",
"KeyAttributes": [],
"LogicalName": "sdkmessageprocessingstep",
"Name": null,
"RowVersion": null
},
"ParentContext": null,
"PostEntityImages": [],
"PreEntityImages": [],
"PrimaryEntityId": "6d81597f-0f9f-e711-8122-000d3aa2331c",
"PrimaryEntityName": "contact",
"RequestId": null,
"SecondaryEntityName": "none",
"SharedVariables": [{
"key": "ChangedEntityTypes",
"value": [{
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "feedback",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "contract",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "salesorder",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "connection",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "socialactivity",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "postfollow",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "incident",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "invoice",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "entitlement",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "lead",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "opportunity",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "quote",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "socialprofile",
"value": "Update"
}, {
"__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
"key": "contact",
"value": "Update"
}]
}],
"Stage": 30,
"UserId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff"
},
"PostEntityImages": [{
"key": "AsynchronousStepPrimaryName",
"value": {
"Attributes": [{
"key": "fullname",
"value": "James Glynn (sample)"
}, {
"key": "contactid",
"value": "6d81597f-0f9f-e711-8122-000d3aa2331c"
}],
"EntityState": null,
"FormattedValues": [],
"Id": "6d81597f-0f9f-e711-8122-000d3aa2331c",
"KeyAttributes": [],
"LogicalName": "contact",
"RelatedEntities": [],
"RowVersion": null
}
}],
"PreEntityImages": [],
"PrimaryEntityId": "6d81597f-0f9f-e711-8122-000d3aa2331c",
"PrimaryEntityName": "contact",
"RequestId": null,
"SecondaryEntityName": "none",
"SharedVariables": [],
"Stage": 40,
"UserId": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff"
}
重要
当整个 HTTP 有效负载的大小超过 256 KB 时, x-ms-dynamics-msg-size-exceeded 将包含标头并删除以下 RemoteExecutionContext 属性:
某些操作不包括这些属性。
从插件或工作流活动调用 WebHook
由于 WebHook 是一种服务终结点,因此无需使用插件或工作流活动注册步骤即可调用它。 此方法的工作方式与 Azure 服务总线终结点的工作方式相同。 您需要向 接口提供 IServiceEndpointNotificationService。 有关详细信息,请参阅以下 Azure 服务总线示例:
排查 WebHook 注册问题
Webhook 相对简单。 服务发送请求并评估响应。 系统无法分析使用响应正文返回的任何数据。 它只查看响应 StatusCode 值。
超时为 60 秒。 通常,如果在超时期限之前未返回任何响应,或者响应 StatusCode 值不在 2xx 指示成功的范围内,则操作将失败。 当返回的错误为下表中的错误,将抛出异常:
| 状态码 | Description |
|---|---|
502 |
错误的网关 |
503 |
服务不可用 |
504 |
网关超时 |
这些错误表示可能通过另一次尝试解决的网络问题。 仅当返回这些错误代码时,WebHook 服务才会再尝试一次。
异步 Webhook(网络钩子)
如果您将 Web 钩子注册为异步处理,您可以检查系统作业以获取错误的详细信息。 有关更多信息,请参阅 查询给定步骤中的失败异步作业。
同步 Webhook
选择使用同步执行模式时,将向应用程序用户报告失败,并显示终结点不可用错误对话,告知用户 Webhook 服务终结点可能配置不正确或不可用。 该对话允许您下载日志文件来获取有关错误的详细信息。
注释
为同步步骤注册 Webhook 时,它会立即将执行上下文数据发送到配置的终结点。 如果在发送请求后发生错误,则数据操作会回滚,但无法召回发送到配置的终结点的请求。
后续步骤
注册 WebHook
使用请求日志记录站点测试 WebHook 注册
另请参阅
编写插件
注册插件
Dataverse 中的异步服务
示例:Azure 感知自定义插件
示例:Azure 感知自定义工作流活动
Azure Functions
ServiceEndpoint 表
SdkMessageProcessingStep 表
AsynchronousOperations 表
RemoteExecutionContext
IServiceEndpointNotificationService