Partager via


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

Utilisez des webhooks pour envoyer des événements de serveur Microsoft Dataverse à une application web externe. Cet article explique les données de requête envoyées par Dataverse et comment les webhooks vous aident à créer des gestionnaires externes pour les événements serveur.

En utilisant des webhooks, les développeurs et les éditeurs de logiciels indépendants peuvent intégrer des données Dataverse à leur propre code personnalisé hébergé sur des services externes. Grâce au modèle webhooks, vous pouvez sécuriser votre point de terminaison à l’aide d’un en-tête d’authentification ou de clés de paramètre de chaîne de requête. Cette approche est plus simple que le modèle d’authentification SAP que vous pouvez utiliser actuellement pour l’intégration d’Azure Service Bus.

Lorsque vous décidez entre le modèle webhook et l’intégration d’Azure Service Bus, gardez à l’esprit les points suivants :

  • Azure Service Bus fonctionne pour le traitement à grande échelle et fournit un mécanisme de mise en file d’attente complète 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 activent 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

L’utilisation de webhooks implique trois parties :

  • la création ou la configuration d’un service pour traiter les requêtes de webhook ;
  • Inscription d’une étape de webhook sur le service Dataverse.
  • l’appel d’un webhook à partir d’un plug-in ou d’une activité de workflow personnalisée.

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, commencez par apprendre à inscrire un WebHook. Pour plus d’informations, consultez Inscrire un WebHook.

Après avoir inscrit un exemple de WebHook, utilisez un site de journalisation des demandes pour examiner les données contextuelles passées. Pour plus d’informations, consultez Tester l'enregistrement de WebHook avec le site de journalisation des requêtes.

Conseil / Astuce

L’exécution des étapes permettant d’inscrire un WebHook de test et d’examiner les données contextuelles passées facilite la compréhension des autres 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 que vous pouvez appliquer à 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 de conseils sur une solution spécifique. Au lieu de cela, il décrit les données que Dataverse transmet à votre service qui permettent à votre service d’ajouter de la valeur.

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

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

Chaîne de requête

Les seules données que vous transmettez en tant que chaîne de requête sont les valeurs d’authentification si vous configurez le WebHook 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 , utilisez les paires clé/valeur dont votre service a besoin.

Vous pouvez vous attendre à ce que votre service reçoive les données suivantes :

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. La plateforme utilise cette propriété pour la prévention des boucles infinies. Dans la plupart des cas, vous pouvez ignorer cette propriété. Lors de l’utilisation du support technique, cette valeur peut être utilisée pour interroger les données de télémétrie afin de comprendre ce qui s’est produit pendant toute l’opération.
x-ms-dynamics-msg-size-exceeded Envoyé uniquement lorsque la taille de charge utile HTTP dépasse 256 Ko.

Corps de la demande

Le corps contient une chaîne qui représente la valeur JSON d’une instance de la RemoteExecutionContext classe. 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. La façon dont vous choisissez d’analyser ces données dépend de la technologie que vous utilisez et de vos préférences.

L’exemple suivant montre les 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 entière dépasse 256 Ko, l’en-tête x-ms-dynamics-msg-size-exceeded est inclus et les propriétés suivantes RemoteExecutionContext sont supprimées :

Certaines opérations n’incluent 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 l’invoquer sans inscrire d’étape en utilisant un plug-in ou une activité de workflow. Cette approche fonctionne 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, consultez 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 analyser aucune donnée retournée avec le corps de la réponse. Elle examine uniquement la valeur de réponse StatusCode .

Le délai d’attente est de 60 secondes. En règle générale, si aucune réponse n’est retournée avant la période d’expiration ou si la valeur de réponse StatusCode n’est pas comprise dans la 2xx plage pour indiquer la réussite, l’opération é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 tentative supplémentaire uniquement lorsque ces codes d’erreur sont retournés.

Webhooks asynchrones

Si vous inscrivez votre webhook pour qu’il s’exécute 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

Lorsque vous inscrivez un webhook pour une étape synchrone, il 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 requête, 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