Webhook を使用して、Microsoft Dataverse サーバー イベントを外部 Web アプリケーションに送信します。 この記事では、Dataverse が送信する要求データと、Webhook を使用してサーバー イベントの外部ハンドラーを構築する方法について説明します。
開発者と ISV は、Webhook を使用して、Dataverse データを外部サービスでホストされる独自のカスタム コードと統合できます。 Webhook モデルを使用すると、認証ヘッダーまたはクエリ文字列パラメーター キーを使用してエンドポイントをセキュリティで保護できます。 この方法は、Azure Service Bus 統合に現在使用している SAS 認証モデルよりも簡単です。
Webhook モデルと Azure Service Bus の統合を決定するときは、次の点に留意してください。
- Azure Service Bus は、大規模な処理に対応し、Dataverse が多数のイベントをプッシュしている場合に完全なキュー メカニズムを提供します。
- Webhook は、ホストされている Web サービスがメッセージを処理できる範囲内でしか拡張できません。
- Webhook では、同期ステップと非同期ステップが有効になります。 Azure Service Bus では、非同期のステップのみ可能です。
- webhook は JSON ペイロードの送信 POST 要求のみを送信し、任意のプログラミング言語または任意の場所でホストされる Webアプリケーションで使用できます。
- Webhook と Azure Service Bus の両方をプラグインまたはカスタム ワークフロー アクティビティから呼び出すことができます。
概要
Webhook の使用には、次の 3 つの部分が含まれます。
- Webhook リクエストを処理するサービスの作成または設定。
- Dataverse サービスに Webhook ステップを登録する。
- プラグインまたはカスタム ワークフロー アクティビティから Webhook を呼び出す。
テスト WebHook を登録することから始める
Dataverse から WebHook 要求を使用するようにサービスを作成および構成する方法を理解するには、まず WebHook を登録する方法を学習します。 詳細については、「 WebHook の登録」を参照してください。
WebHook の例を登録したら、要求ログ サイトを使用して、渡されたコンテキスト データを調べます。 詳細については、 要求ログ サイトでの WebHook 登録のテストに関するページを参照してください。
ヒント
テスト WebHook を登録する手順を完了し、渡されたコンテキスト データを調べると、このトピックの残りの情報を理解しやすくなります。 これらの手順を完了し、このトピックに戻ります。
WebHook 要求を使用するサービスを作成または構成する
Webhook は、さまざまなテクノロジを使用して適用できる単なるパターンです。 使用する必要のあるフレームワーク、プラットフォーム、またはプログラミング言語はありません。 自分のスキルやノウハウを駆使して適切なソリューションを提供します。
Azure Functions は、Webhook を使用してソリューションを提供する優れた方法を提供しますが、これは要件ではありません。 このセクションでは、特定のソリューションに関するガイダンスを提供しません。 代わりに、Dataverse がサービスに渡すデータを記述して、サービスが価値を追加できるようにします。
要求ログ サイトでの WebHook 登録のテストで示されているように、テスト WebHook ステップを登録し、要求ログ サイトを使用して、アプリケーションで処理できる特定の種類のデータをキャプチャできます。
サービスに受け渡されるデータ
要求には、クエリ文字列、ヘッダー データ、要求本文の 3 種類のデータが含まれています。
クエリ文字列
クエリ文字列として渡すデータは、「認証オプション」の説明に従って WebhookKey または HttpQueryString オプションを使用するように WebHook を構成する場合の認証値のみです。
ヘッダー データ
HttpHeader 認証オプションを選択した場合は、サービスに必要なキーと値のペアを使用します。
サービスが次のデータを受け取ると予想できます。
| Key | 値の説明 |
|---|---|
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 |
|---|---|
| メッセージ | Update |
| 主エンティティ | 連絡先 |
| 副エンティティ | none |
| フィルタリング属性 | 名、姓 |
| ユーザーのコンテキストで実行する | 呼び出し元ユーザー |
| 実行順序 | 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"
}
Important
HTTP ペイロード全体のサイズが 256 KB を超えると、 x-ms-dynamics-msg-size-exceeded ヘッダーが含まれており、次の RemoteExecutionContext プロパティが削除されます。
一部の操作には、これらのプロパティが含まれていません。
プラグインまたはワークフロー アクティビティから WebHook を呼び出す
WebHook は一種のサービス エンドポイントであるため、プラグインまたはワークフロー アクティビティを使用してステップを登録せずに呼び出すことができます。 この方法は、Azure Service Bus エンドポイントの場合と同じように機能します。 ServiceEndpointId を IServiceEndpointNotificationService インターフェイスに提供する必要があります。 詳細については、次の Azure Service Bus サンプルを参照してください。
WebHook 登録のトラブルシューティング
webhook 比較的簡単です。 サービスは要求を送信し、応答を評価します。 システムは、応答の本文で返されたデータを解析できません。 応答 StatusCode 値のみを確認します。
タイムアウトは 60 秒です。 一般に、タイムアウト期間の前に応答が返されない場合、または応答 StatusCode 値が成功を示す 2xx 範囲内にない場合、操作は失敗します。 返されたエラーが次の表にある場合は例外です。
| ステータスコード | Description |
|---|---|
502 |
誤ったゲートウェイ |
503 |
サービス利用不可 |
504 |
ゲートウェイのタイムアウト |
これらのエラーは、再度の試みによって解決される可能性がある問題を示しています。 WebHook サービスは、これらのエラー コードが返された場合にのみもう 1 回試行します。
非同期 Webhooks
非同期的に実行するように Web フックを登録した場合は、システム ジョブでエラーの詳細を確認できます。 詳細については、「特定の ステップで失敗した非同期ジョブのクエリ」を参照してください。
同期Webフック
同期実行モードを選択すると、失敗はエンドポイントを使用できませんというエラー ダイアログによってアプリケーションのユーザーに報告され、webhook のサービス エンドポイントが正しく構成されていないか、利用できないことが通知されます。 ダイアログでは、エラーの詳細を取得するためにログ ファイルをダウンロードすることができます。
注
同期ステップ用に Webhook を登録すると、構成されたエンドポイントに実行コンテキスト データがすぐに送信されます。 要求の送信後にエラーが発生した場合、データ操作はロールバックしますが、構成されたエンドポイントに送信された要求を取り消すことはできません。
次のステップ
WebHook を登録する
要求ログ サイトで WebHook 登録をテストする
こちらも参照ください
プラグインを記述する
プラグインの登録
Dataverse の非同期サービス
サンプル: Azure 対応のカスタム プラグイン
サンプル: Azure 対応のユーザー定義ワークフロー活動
Azure Functions
ServiceEndpoint テーブル
SdkMessageProcessingStep テーブル
AsynchronousOperations テーブル
RemoteExecutionContext
IServiceEndpointNotificationService