Compartilhar via


Usar webhooks para criar manipuladores externos para eventos de servidor

Use webhooks para enviar eventos de servidor do Microsoft Dataverse para um aplicativo Web externo. Este artigo explica os dados que o Dataverse envia nas solicitações e como os webhooks ajudam você a desenvolver manipuladores externos para eventos do servidor.

Usando webhooks, desenvolvedores e ISVs podem integrar dados do Dataverse com seu próprio código personalizado hospedado em serviços externos. O modelo de webhook permite que você proteja o ponto de extremidade usando um cabeçalho de autenticação ou chaves de parâmetros de sequência de caracteres de consulta. Essa abordagem é mais simples do que o modelo de autenticação SAS que você pode usar atualmente para a integração do Barramento de Serviço do Azure.

Ao decidir entre o modelo de webhook e a integração do Barramento de Serviço do Azure, tenha estes pontos em mente:

  • Azure Service Bus é adequado para processamento em alta escala e fornece um mecanismo completo de enfileiramento caso o Dataverse esteja enviando muitos eventos por push.
  • Os webhooks podem ser redimensionados apenas no ponto em que o serviço Web hospedado pode processar as mensagens.
  • Os webhooks habilitam etapas síncronas e assíncronas. O Barramento de Serviço do Azure permite somente etapas assíncronas.
  • Os webhooks enviam solicitações POST com conteúdo JSON e podem ser usados por qualquer linguagem de programação ou aplicativo Web hospedado em qualquer lugar.
  • Os webhooks e o Barramento de Serviço do Azure podem ser invocados de um plug-in ou de uma atividade de fluxo de trabalho personalizada.

Introdução

O uso de webhooks envolve três partes:

  • Criar ou configurar um serviço para consumir solicitações de webhook.
  • Registrando a etapa do webhook no serviço Dataverse.
  • Invocar um webhook usando um plug-in ou uma atividade de fluxo de trabalho personalizada.

Inicie registrando um WebHook de teste

Para entender como criar e configurar um serviço para consumir uma solicitação de WebHook do Dataverse, comece aprendendo a registrar um WebHook. Para obter mais informações, consulte Registrar um WebHook.

Depois de registrar um WebHook de exemplo, use um site de registro de solicitação para examinar os dados contextuais que são transmitidos. Para obter mais informações, consulte Testar o registro do WebHook com o site de registro de solicitação.

Dica

Concluir as etapas para registrar um WebHook de teste e examinar os dados contextuais que são passados torna o restante das informações neste tópico mais fácil de entender. Conclua estas etapas e retorne a este tópico.

Criar ou configurar um serviço para consumir solicitações do WebHook

Webhooks são simplesmente um padrão que você pode aplicar usando uma ampla gama de tecnologias. Não há estruturas, plataformas ou linguagens de programação necessárias que você deve usar. Use as habilidades e o conhecimento que tem para fornecer a solução apropriada.

O Azure Functions fornece uma excelente maneira de fornecer uma solução usando Webhooks, mas não é um requisito. Esta seção não fornece diretrizes para uma solução específica. Em vez disso, descreve os dados que o Dataverse passa para seu serviço que permitem que seu serviço adicione valor.

Conforme demonstrado no registro do WebHook de teste com o site de registro de solicitação, você pode registrar uma etapa de teste do WebHook e usar o site de registro de solicitação para capturar os tipos específicos de dados que seu aplicativo pode processar.

Dados passados para o serviço

A solicitação inclui três tipos de dados: cadeia de caracteres de consulta, dados de cabeçalho e corpo da solicitação.

Cadeia de consulta

Os únicos dados que você passa como uma cadeia de caracteres de consulta são os valores de autenticação se você configurar o WebHook para usar as opções WebhookKey ou HttpQueryString , conforme descrito nas opções de Autenticação.

Dados de cabeçalho

Se você escolher a opção de autenticação HttpHeader , use os pares chave/valor exigidos pelo serviço.

Você pode esperar que seu serviço receba os seguintes dados:

Chave Descrição do valor
x-ms-dynamics-organization O nome de domínio do ambiente que envia a solicitação
x-ms-dynamics-entity-name O nome lógico da tabela passada nos dados de contexto de execução.
x-ms-dynamics-request-name O nome do evento para o qual a etapa do WebHook foi registrada.
x-ms-correlation-request-id Identificador exclusivo para rastrear qualquer tipo de extensão. A plataforma usa essa propriedade para prevenção de loop infinito. Na maioria dos casos, você pode ignorar essa propriedade. Ao trabalhar com suporte técnico, esse valor pode ser usado para consultar a telemetria para entender o que ocorreu durante toda a operação.
x-ms-dynamics-msg-size-exceeded Enviado somente quando o tamanho da carga HTTP excede 256 KB.

Corpo da solicitação

O corpo contém uma cadeia de caracteres que representa o valor JSON de uma instância da RemoteExecutionContext classe. Esses são os mesmos dados enviados às integrações do Azure Service Bus.

O serviço criado deve analisar esses dados para extrair os itens relevantes de informações para que seu serviço forneça sua função. A maneira como você escolhe analisar esses dados depende da tecnologia que você está usando e de suas preferências.

O exemplo a seguir mostra os dados JSON serializados passados para uma etapa registrada com as seguintes propriedades:

Propriedade Descrição
Mensagem Atualização
Entidade Principal contato
Entidade Secundária nenhum
Atributos de Filtragem firstname,lastname
Executar no contexto do usuário Usuário da Chamada
Ordem de Execução 1
Etapa de Execução do Pipeline de Eventos Pós-Operação
Modo de Execução Assíncrono
{
    "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

Quando o tamanho de toda a carga HTTP excede 256 KB, o x-ms-dynamics-msg-size-exceeded cabeçalho é incluído e as seguintes RemoteExecutionContext propriedades são removidas:

Algumas operações não incluem essas propriedades.

Acionar um WebHook a partir de uma atividade de plug-in ou fluxo de trabalho

Como WebHook é uma espécie de endpoint de serviço, você pode invocá-lo usando um plug-in ou uma atividade de fluxo de trabalho, sem registrar uma etapa. Essa abordagem funciona da mesma maneira que para um ponto de extremidade do Barramento de Serviço do Azure. Você precisa fornecer o ServiceEndpointId à interface IServiceEndpointNotificationService. Para mais informações, consulte os exemplos a seguir do Barramento de Serviço do Azure:

Solucionar problemas de registros do WebHook

Webhooks são relativamente simples. O serviço envia a solicitação e avalia a resposta. O sistema não consegue interpretar nenhum dado retornado com o corpo da resposta. Ele examina apenas o valor da resposta StatusCode .

O tempo limite é de 60 segundos. Geralmente, se nenhuma resposta for retornada antes do período de tempo limite ou se o valor da resposta StatusCode não estiver dentro do 2xx intervalo para indicar êxito, a operação falhará. A exceção é quando o erro retornado estiver na tabela a seguir:

CódigoDeStatus Descrição
502 Gateway inválido
503 Serviço indisponível
504 Tempo de Espera do Gateway (Gateway Timeout)

Esses erros indicam um problema de rede que pode ser resolvido com outra tentativa. O serviço WebHook faz mais uma tentativa somente quando esses códigos de erro são retornados.

Webhooks assíncronos

Se você registrar seu web hook para ser executado de forma assíncrona, poderá examinar a Tarefa do Sistema para obter detalhes sobre o erro. Para obter mais informações, consulte Trabalhos assíncronos com falha na consulta para uma determinada etapa.

Webhooks síncronos

Quando você optar por usar um modo de execução síncrono, qualquer falha será relatada novamente ao usuário do aplicativo com uma caixa de diálogo de erro Ponto de extremidade indisponível informando ao usuário que o ponto de extremidade de serviço do webhook pode estar configurado incorretamente ou não está disponível. A caixa de diálogo permitirá que você baixe um arquivo de log para obter detalhes sobre quaisquer erros.

Observação

Quando você registra um webhook para uma etapa síncrona, ele imediatamente envia os dados do contexto de execução para o endpoint configurado. Se ocorrer um erro após o envio da solicitação, a operação de dados será revertida, mas a solicitação enviada ao ponto de extremidade configurado não poderá ser retirada.

Próximas Etapas 

Registrar um WebHook
Testar o registro do WebHook com o site de registro de requisições

Consulte também

Escrever um plug-in
Registrar um plug-in
Serviço assíncrono no Dataverse
Exemplo: Plug-in personalizado com reconhecimento do Azure
Exemplo: Atividade de fluxo de trabalho personalizada com reconhecimento do Azure
Azure Functions
Tabela ServiceEndpoint
Tabela SdkMessageProcessingStep
Tabela Assíncrona de Operations
RemoteExecutionContext
IServiceEndpointNotificationService