Compartir a través de


Utilice webhooks para crear controladores externos para eventos de servidor

Use webhooks para enviar eventos de servidor de Microsoft Dataverse a una aplicación web externa. En este artículo se explican los datos de solicitud que Dataverse envía y cómo los webhooks le ayudan a crear controladores externos para eventos de servidor.

Mediante el uso de webhooks, los desarrolladores e ISV pueden integrar datos de Dataverse con su propio código personalizado hospedado en servicios externos. Con el modelo de webhooks, puede proteger el extremo usando un encabezado de autenticación o claves de parámetro de string de consulta. Este enfoque es más sencillo que el modelo de autenticación de SAS que puede usar actualmente para la integración de Azure Service Bus.

Al decidir entre el modelo de webhook y la integración de Azure Service Bus, tenga en cuenta estos puntos:

  • Azure Service Bus funciona para el procesamiento a gran escala y proporciona un mecanismo de puesta en cola completo si Dataverse está procesando muchos eventos.
  • Los webhooks solo pueden escalar hasta el punto en el que su servicio web hospedado pueda manejar los mensajes.
  • Los webhooks permiten pasos sincrónicos y asincrónicos. Azure Service Bus solo permite pasos asincrónicos.
  • Los webhooks envían solicitudes POST con carga JSON y pueden ser consumidos por cualquier lenguaje de programación o aplicación web hospedada en cualquier lugar.
  • Tanto los webhooks como Azure Service Bus se pueden invocar desde una actividad de flujo de trabajo personalizada o complemento.

Empieza ahora

El uso de webhooks implica tres partes:

  • Crear o configurar un servicio para consumir solicitudes de webhook.
  • Registrar el paso de webhook en el servicio de Dataverse.
  • Llamar un webhook desde un complemento o actividad personalizada de flujo de trabajo.

Empiece por registrar un webHook de prueba

Para comprender cómo crear y configurar un servicio para consumir una solicitud de WebHook desde Dataverse, empiece por aprender a registrar un webHook. Para obtener más información, consulte Registrar un WebHook.

Después de registrar un WebHook de ejemplo, use un sitio de registro de solicitudes para examinar los datos contextuales que se pasan. Para obtener más información, consulte Probar el registro de WebHook con el sitio de registro de solicitudes.

Sugerencia

Completar los pasos para registrar un webHook de prueba y examinar los datos contextuales que se pasan hace que el resto de la información de este tema sea más fácil de entender. Complete estos pasos y vuelva a este tema.

Creación o configuración de un servicio para consumir solicitudes de WebHook

Los webhooks son simplemente un patrón que se puede aplicar mediante una amplia gama de tecnologías. No es necesario utilizar marcos, plataformas o lenguajes de programación. Utilice las capacidades y conocimiento que tiene para proporcionar la solución apropiada.

Azure Functions proporciona una manera excelente de ofrecer una solución mediante webhooks, pero no es un requisito. Esta sección no proporciona instrucciones para una solución específica. En su lugar, describe los datos que Dataverse pasa a tu servicio, lo que permite agregar valor.

Como se muestra en Probar el registro de WebHook con el sitio de registro de solicitudes, puede registrar un paso de webHook de prueba y usar el sitio de registro de solicitudes para capturar los tipos específicos de datos que la aplicación puede procesar.

Datos que se transmiten al servicio

La solicitud incluye tres tipos de datos: cadena de consulta, datos de encabezado y cuerpo de la solicitud.

Cadena de consulta

Los únicos datos que se pasan como una cadena de consulta son los valores de autenticación si configura el WebHook para usar las opciones WebhookKey o HttpQueryString , como se describe en Opciones de autenticación.

Datos de encabezado

Si elige la opción de autenticación HttpHeader , use los pares clave-valor que requiere el servicio.

Puede esperar que el servicio reciba los datos siguientes:

Key Descripción del valor
x-ms-dynamics-organization Nombre de dominio del entorno que envía la solicitud
x-ms-dynamics-entity-name Nombre lógico de la tabla pasada en los datos de contexto de ejecución.
x-ms-dynamics-request-name Nombre del evento para el que se registró el paso de WebHook.
x-ms-correlation-request-id Identificador único para realizar un seguimiento de cualquier tipo de extensión. La plataforma usa esta propiedad para la prevención de bucles infinitos. En la mayoría de los casos, puede ignorar esta propiedad. Al trabajar con soporte técnico, este valor se puede usar para consultar la telemetría para comprender lo que se ha producido durante toda la operación.
x-ms-dynamics-msg-size-exceeded Se envía solo cuando el tamaño de carga HTTP supera los 256 KB.

Cuerpo de la solicitud

El cuerpo contiene una cadena que representa el valor JSON de una instancia de la RemoteExecutionContext clase . Estos son los mismos datos que se pasan a las integraciones de Azure Service Bus.

El servicio que cree debe analizar estos datos para extraer los elementos relevantes de información para que su servicio proporcione su función. La forma de analizar estos datos depende de la tecnología que use y sus preferencias.

En el ejemplo siguiente se muestran los datos JSON serializados que se pasan para un paso registrado con las siguientes propiedades:

Propiedad Description
Mensaje Update
Entidad principal contacto
Entidad secundaria none
Atributos de filtro firstname,lastname
Ejecutar en el contexto del usuario Usuario que llama
Pedido de ejecución 1
Fase de canalización de eventos de ejecución PostOperation
Modo de ejecución Asincrónica
{
    "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"
}

Importante

Cuando el tamaño de toda la carga HTTP supera los 256 KB, se incluye el x-ms-dynamics-msg-size-exceeded encabezado y se quitan las siguientes RemoteExecutionContext propiedades:

Algunas operaciones no incluyen estas propiedades.

Invocar un webHook desde un complemento o una actividad de flujo de trabajo

Dado que un WebHook es un tipo de punto de conexión de servicio, puede invocarlo sin registrar un paso mediante una actividad de complemento o flujo de trabajo. Este enfoque funciona del mismo modo que para un punto de conexión de Azure Service Bus. Es necesario proporcionar el ServiceEndpointId para la interfaz IServiceEndpointNotificationService. Para más información, consulte los siguientes ejemplos de Azure Service Bus:

Solución de problemas de registros de WebHook

Los webhooks son relativamente simples. El servicio envía la solicitud y evalúa la respuesta. El sistema no puede analizar los datos devueltos con el cuerpo de la respuesta. Solo examina el valor de respuesta StatusCode .

El tiempo de espera es de 60 segundos. Por lo general, si no se devuelve ninguna respuesta antes del período de tiempo de espera o si el valor de la respuesta StatusCode no está dentro del 2xx intervalo para indicar que la operación se ha realizado correctamente, se produce un error en la operación. La excepción se produce cuando el error devuelto se encuentra en la tabla siguiente:

Código de estado Description
502 Puerta de enlace incorrecta
503 Servicio no disponible
504 Tiempo de espera de puerta de enlace

Estos errores indican un problema de red que se puede resolver con otro intento. El servicio WebHook realiza un intento más solo cuando se devuelven estos códigos de error.

Webhooks asincrónicos

Si registra el webhook para que se ejecute de forma asincrónica, puede examinar el trabajo del sistema para obtener más información sobre el error. Para obtener más información, consulte Consultar trabajos asincrónicos que dan error para un paso determinado.

Webhooks sincrónicos

Cuando decida usar un modo de ejecución sincrónica cualquier error se notificará al usuario de la aplicación con un diálogo de error Extremo no disponible que informa al usuario de que el punto de conexión del servicio webhook puede estar configurado incorrectamente o no está disponible. El diálogo le permitirá descargar un archivo de registro para obtener los detalles de cualquier error.

Nota:

Al registrar un webhook para un paso sincrónico, envía los datos de contexto de ejecución al punto de conexión configurado inmediatamente. Si se produce un error después de enviar la solicitud, la operación de datos se revierte, pero la solicitud enviada al punto de conexión configurado no se puede recuperar.

Pasos siguientes

Registrar un WebHook
Probar el registro de webhook con un sitio de registro de solicitud

Consulte también

Escribir un complemento
Registrar un complemento
Servicio asincrónico en Dataverse
Ejemplo: Complemento personalizado habilitado para Azure
Ejemplo: Actividad personalizada de flujo de trabajo habilitada para Azure
Funciones de Azure
Tabla ServiceEndpoint
Tabla SdkMessageProcessingStep
Tabla de Operaciones Asincrónicas
RemoteExecutionContext
IServiceEndpointNotificationService