Skip to content

Cloud & Integration

Guidance for the parts of a project that sit outside Dataverse itself — Azure Functions, Logic Apps, API Management/gateways, and similar integration components referenced in Solution Architecture.

Choose the right place for the logic

Before writing an integration, decide where it runs — this is the highest-leverage decision:

Need Use
Synchronous business rule on a Dataverse write, fast and transactional Plugin (server-side)
Reaction to a Dataverse event, no strict latency need, citizen-maintainable Power Automate cloud flow
Long-running, fan-out, heavy compute, or orchestration across systems Azure (Functions / Logic Apps / Service Bus)
Synchronous call out to an external system from a write Plugin + the HTTP/Key Vault helpers below — but mind the 2-minute sandbox limit

DGT-INT-010 — The platform sandbox kills a plugin at two minutes and you don't control retry semantics finely — anything slow, bursty, or that must not block the user belongs in async (a flow, or Azure behind a queue), not in a synchronous plugin.

Calling out from a plugin

When a plugin does call an external service, prefer a managed identity via [ManagedIdentityRegistration] over a stored client secret or Key Vault lookup — Digitall.Plugins no longer ships Key Vault/SharePoint/HTTP helper modules (removed in 2.0.0; see DIGITALL Assembly → Add-on modules), so calling another service means either the managed-identity path above or calling the target SDK/REST API directly with your own HttpClient.

DGT-INT-020 — Use a single, lazily-created, shared HttpClient regardless of which path you take — never create one per invocation. Per-call clients exhaust sockets under load and are one of the standard causes of intermittent outbound-call failures from plugins.

DGT-INT-030 — Every external call from a plugin sets an explicit timeout (well under the two-minute sandbox budget, so your error handling runs instead of the sandbox killing the worker) and disables connection keep-alive — the sandbox recycles worker processes, and kept-alive connections to a recycled worker surface as sporadic, unreproducible failures. With HttpClient that means sending Connection: close (DefaultRequestHeaders.ConnectionClose = true); the legacy HttpWebRequest.KeepAlive = false form in Microsoft's sample achieves the same. See Microsoft's guidance on external calls.

Dataverse service protection limits

Dataverse throttles API consumers per user and web server in a 5-minute sliding window: 6,000 requests, 20 minutes combined execution time, ~52 concurrent requests — see Microsoft's service protection documentation.

DGT-INT-040 — Every integration that talks to Dataverse must handle HTTP 429 with the Retry-After header — an integration that treats 429 as a fatal error, or retries immediately in a tight loop, fails exactly when load is highest. Use Microsoft.PowerPlatform.Dataverse.Client.ServiceClient, which honors Retry-After automatically; hand-rolled HTTP clients must implement the same backoff.

For bulk workloads, note that large batches are not a remedy for throttling — batch execution time counts against the same limits. Microsoft's guidance is small batches (~10) with controlled parallelism, preferring the bulk-operation APIs (CreateMultiple/UpdateMultiple), and letting the server dictate throughput via Retry-After — see optimizing bulk performance and sending parallel requests.

DGT-INT-050 — Never use the Dataverse Search API for bulk or programmatic mass queries — it is rate-limited to roughly one request per second per user and is built for interactive search. Bulk reads use the Web API / SDK with paging, or FetchXML aggregation.

Eventing out of Dataverse

  • DGT-INT-060 — Push Dataverse events to Azure asynchronously via the service-endpoint registration (Azure Service Bus / event publishing) — not with a plugin that POSTs to an external endpoint synchronously. The service endpoint gives you durable delivery and retry from the platform; a synchronous POST makes the remote system's downtime your transaction's downtime.
  • Webhooks suit a real-time, synchronous external call, but the remote endpoint then sits in your transaction's critical path — treat its latency and failure as your plugin's.

Bringing external data in

  • Virtual tables surface external data as Dataverse rows read-only (or read/write) — see Custom API & Data Providers.
  • Custom connectors wrap an external API for use from flows and canvas apps; keep their definitions in source control with the rest of the project.

ALM for these components

Azure-side components live in their own repositories per Solution Architecture, but follow the same ALM conventions — source control, SemVer, CI, and gated deployment — adapted to their stack (Bicep/Terraform, Functions deploy, etc.). Connectors and connection references they depend on are governed by the active DLP policy — check it before building, not after.