Partager via


Utiliser des webhooks pour créer des gestionnaires externes pour les événements de serveur

Avec Microsoft Dataverse, vous pouvez envoyer des données sur les événements qui se produisent sur le serveur à une application web à l’aide de webhooks. Une webhook est un protocole HTTP léger permettant de connecter des API web et des services avec un modèle de publication/abonnement. Les expéditeurs de webhooks avertissent les destinataires à propos d’événements en adressant aux points de terminaison du destinataire des demandes comportant certaines informations sur les événements.

Les webhooks permettent aux développeurs et aux éditeurs de logiciels indépendants d’intégrer des données Dataverse à leur propre code personnalisé hébergé sur des services externes. En utilisant le modèle WebHook, vous pouvez sécuriser votre point de terminaison à l'aide de clés d'en-tête d'authentification ou de paramètres de chaîne de requête. Cette méthode est plus simple que le modèle d’authentification SAS que vous utilisez peut-être actuellement pour l’intégration de Azure Service Bus.

Lorsque vous décidez entre le modèle WebHook et l’intégration d’Azure Service Bus, voici quelques éléments à garder à l’esprit :

  • Azure Service Bus fonctionne pour le traitement à grande échelle et fournit un mécanisme de mise en file d’attente complet si Dataverse envoie de nombreux événements.
  • Les webhooks ne peuvent évoluer que jusqu’au point auquel votre service Web hébergé peut gérer les messages.
  • Les webhooks permettent des étapes synchrones et asynchrones. Azure Service Bus autorise uniquement les étapes asynchrones.
  • Les webhooks envoient des requêtes POST avec une charge utile JSON et sont consommables par n’importe quel langage de programmation ou application Web hébergée n’importe où.
  • Les Webhooks et Azure Service Bus peuvent être appelés à partir d’une activité de plug-in ou de flux de travail personnalisé.

Get Started

Il y a trois parties pour utiliser les webhooks :

  • Création ou configuration d’un service pour consommer des requêtes WebHook.
  • Enregistrement de l’étape WebHook sur le service Dataverse ou
  • Appel d’un WebHook à partir d’une activité de plug-in ou de flux de travail personnalisé.

Commencez par inscrire un WebHook de test

Pour comprendre comment créer et configurer un service pour utiliser une requête WebHook à partir de Dataverse, il est utile de commencer par comprendre comment inscrire un WebHook. Plus d’informations : Inscrire un WebHook

Lorsque vous avez inscrit un exemple de WebHook, vous pouvez utiliser un site de journalisation des demandes pour examiner les données contextuelles qui seront transmises. Plus d’informations : Tester l’enregistrement WebHook avec le site de journalisation des demandes

Conseil / Astuce

L’exécution des étapes permettant d’inscrire un WebHook de test et d’examiner les données contextuelles passées permet de faciliter la compréhension du reste des informations de cette rubrique. Effectuez ces étapes et revenez à cette rubrique.

Créer ou configurer un service pour consommer des requêtes WebHook

Les webhooks sont simplement un modèle qui peut être appliqué à l’aide d’un large éventail de technologies. Ils ne requièrent aucun framework, plateforme ou langage de programmation particulier. Utilisez vos compétences et vos connaissances pour fournir la solution appropriée.

Azure Functions offre un excellent moyen de fournir une solution à l’aide de Webhooks, mais ce n’est pas une exigence. Cette section ne fournit pas d’instructions par rapport à une solution spécifique, mais décrit plutôt les données qui seront transmises à votre service et lui permettront d’être utile.

Comme illustré dans l'enregistrement de WebHook de test avec le site de journalisation des demandes, vous pouvez enregistrer un WebHook de test et utiliser le site de journalisation des demandes pour capturer les types précis de données que votre application est capable de traiter.

Données transmises au service

Il existe trois types de données dans la requête : chaîne de requête, données d’en-tête et corps de requête.

Chaîne de requête

Le seul type de données qui sera transmis en tant que chaîne de requête peut être les valeurs d’authentification passées si le WebHook est configuré pour utiliser les options WebhookKey ou HttpQueryString , comme décrit dans les options d’authentification.

Données d’en-tête

Si vous choisissez l’option d’authentification HttpHeader, vous devrez utiliser les paire clé/valeur demandées par votre service.

Les autres données que vous pourrez voir transmises à votre service se trouvent dans le tableau ci-dessous :

Key Description de la valeur
x-ms-dynamics-organization Nom de domaine de l’environnement envoyant la requête
x-ms-dynamics-entity-name Nom logique de la table passée dans les données de contexte d’exécution.
x-ms-dynamics-request-name Nom de l’événement pour lequel l’étape WebHook a été inscrite.
x-ms-correlation-request-id Identificateur unique permettant de suivre tout type d’extension. Cette propriété est utilisée par la plateforme pour empêcher les boucles infinies. Dans la plupart des cas, cette propriété peut être ignorée. Cette valeur peut être utilisée pour travailler avec le support technique car elle peut servir à interroger la télémétrie afin de savoir ce qui s’est passé pendant toute l’opération.
x-ms-dynamics-msg-size-exceeded Ne l’envoyez que quand la charge utile HTTP dépasse les 256 Ko.

Corps de la requête

Le corps contient une chaîne représentant la valeur JSON d’une instance de la classe RemoteExecutionContext. Il s’agit des mêmes données que celles transmises aux intégrations Azure Service Bus.

Le service que vous avez créé doit analyser ces données pour extraire les éléments d’informations appropriés pour que votre service assure sa fonction. Votre choix d’analyser ces données dépend de la technologie que vous utilisez et de vos préférences.

Ce qui suit est un exemple de données JSON sérialisées passées pour une étape inscrite avec les propriétés suivantes :

Propriété Descriptif
Message Update
Entité principale contact
Entité secondaire Aucune
Filtrage d’attributs prénom, nom
Exécuter dans le contexte de l’utilisateur Utilisateur appelant
Ordre d’exécution 1
Phase d’exécution dans le pipeline d’événement PostOperation
Mode d’exécution Asynchrone
{
    "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

Lorsque la taille de la charge utile HTTP dépasse 256 Ko, l’en-tête x-ms-dynamics-msg-size-exceeded est inclus et les propriétés RemoteExecutionContext suivantes sont supprimées :

Certaines opérations ne comprennent pas ces propriétés.

Appeler un WebHook à partir d’une activité de plug-in ou de flux de travail

Étant donné qu’un WebHook est un type de point de terminaison de service, vous pouvez également l’appeler sans inscrire d’étape avec un plug-in ou une activité de flux de travail de la même façon que pour un point de terminaison Azure Service Bus. Vous devez indiquer l’ID ServiceEndpointId à l’interface IServiceEndpointNotificationService. Pour plus d’informations, voir les exemples Azure Service Bus suivants :

Résoudre les problèmes d’enregistrements WebHook

les webhooks sont assez simples. Le service envoie la requête et évalue la réponse. Le système ne peut pas analyser les données renvoyées avec le corps de la réponse, il se contente de regarder la valeur du StatusCode de la réponse.

Le délai d’attente est de 60 secondes. En général, si aucune réponse n’est renvoyée avant le délai d’expiration ou si la valeur StatusCode de la réponse n’est pas dans la plage 2xx qui indique la réussite, la requête échoue. Il y a une exception lorsque l’erreur renvoyée est dans le tableau suivant :

StatusCode Descriptif
502 Passerelle incorrecte
503 Service indisponible
504 Délai d’expiration de passerelle

Ces erreurs indiquent un problème de réseau qui peut être résolu lors d’une autre tentative. Le service WebHook effectue une autre tentative uniquement lorsque ces codes d’erreur sont retournés.

Webhooks asynchrones

Si votre webhook est inscrit pour s’exécuter en mode asynchrone, vous pouvez examiner la tâche système pour obtenir des détails sur l’erreur. Pour plus d’informations, voir : Tâches asynchrones de requête échouées pour une étape donnée

Webhooks synchrones

Lorsque vous choisissez d’utiliser un mode d’exécution synchrone, toute défaillance est signalée à l’utilisateur de l’application par une boîte de dialogue d’erreur Point de terminaison non disponible informant l’utilisateur que le point de terminaison du service de webhook peut être configuré incorrectement ou n’est pas disponible. Ce dialogue vous permet de télécharger un fichier journal pour avoir des détails sur les erreurs.

Note

Tout webhook inscrit pour une étape synchrone envoie immédiatement les données de contexte d’exécution au point de terminaison configuré. Si une erreur se produit après l’envoi de la demande, l’opération de données est annulée, mais la demande envoyée au point de terminaison configuré ne peut pas être rappelée.

Étapes suivantes

Inscrire un WebHook
Tester l'enregistrement WebHook avec le site de journalisation des requêtes

Voir aussi

Écrire un plug-in
Enregistrer un plug-in
Service asynchrone dans Dataverse
Exemple : Plug-in personnalisé compatible Azure
Exemple : activité de workflow personnalisée compatible Azure
Azure Functions
Table ServiceEndpoint
Table SdkMessageProcessingStep
Table des Opérations Asynchrones
RemoteExecutionContext
IServiceEndpointNotificationService