AzureAdvanced

Sending Dataverse events to Azure Service Bus

Push Dataverse changes to Azure Service Bus without writing a plugin, then process them in an Azure Function. A clean pattern for integrations.

Prerequisites

  • Azure subscription with a Service Bus namespace and queue
  • Plugin Registration Tool
  • Azure Functions (.NET) basics

What you'll learn

  • Why a queue beats calling external systems from plugins
  • Register a Service Bus endpoint and steps
  • Read the RemoteExecutionContext in an Azure Function
  • Design for retries and duplicates
On this page
  1. The architecture
  2. Set up Service Bus
  3. Register the endpoint
  4. Process messages in an Azure Function
  5. Design for the real world

Calling an external API directly from a plugin is risky: the user waits, and if the other system is down the save fails. A better pattern is to publish an event to a queue and let something else process it.

Dataverse can post messages to Azure Service Bus for you — no custom plugin code needed.

The architecture

  1. A user updates an account in Dataverse.
  2. Dataverse posts the execution context to a Service Bus queue.
  3. An Azure Function reads the message and calls the external system.

If the external system is down, messages wait in the queue and are retried later. Users never notice.

Set up Service Bus

In Azure, create a Service Bus namespace and a queue (for example dataverse-accounts). Create a shared access policy on the queue with Send rights only, and copy its connection string.

Register the endpoint

In the Plugin Registration Tool:

  1. Register → Register New Service Endpoint and paste the connection string.
  2. Choose Queue as the designation type and .NETBinary or JSON as the message format — JSON is easier to read in other languages.
  3. Register a step on the endpoint: message Update, entity account, asynchronous, with filtering attributes for the columns you care about.

Process messages in an Azure Function

With the JSON message format, the message body is the serialised execution context:

C#
public class AccountSync
{
    private readonly ILogger<AccountSync> _log;
    public AccountSync(ILogger<AccountSync> log) => _log = log;

    [Function("AccountSync")]
    public async Task Run(
        [ServiceBusTrigger("dataverse-accounts", Connection = "ServiceBusConnection")] string message)
    {
        using var doc = JsonDocument.Parse(message);
        var root = doc.RootElement;

        var id = root.GetProperty("PrimaryEntityId").GetString();
        var messageName = root.GetProperty("MessageName").GetString();
        _log.LogInformation("Received {Message} for account {Id}", messageName, id);

        // Call your external system here — idempotently.
        await Task.CompletedTask;
    }
}

For .NET, you can instead use the .NETBinary format and deserialise a RemoteExecutionContext with the Dataverse SDK, which gives you typed access to InputParameters and images.

Design for the real world

  • Expect duplicates. Queues deliver at least once. Make processing idempotent — for example, store the last processed version per record.
  • Expect order to vary. Two quick updates may arrive out of order. Compare modifiedon before applying older data.
  • Use dead-lettering. Messages that fail repeatedly move to the dead-letter queue. Monitor it and alert on it.
J / K next or previous article

Jagadeesan P

Found this useful? I share new guides on LinkedIn.

Follow