Callouts to plug-ins: CRM 3.0, 4.0, 2011 and Dataverse side by side

How custom server code changed from CRM 3.0 callouts to CRM 4.0 plug-ins, what CRM 2011 changed again, and what carries through to Dataverse. Includes what broke at each upgrade and how to port an old callout.

Answer first

Custom server code went through three shapes before Dataverse:

  • CRM 3.0 callouts. A class derived from CrmCalloutBase, listed by hand in callout.config.xml in each server’s assembly folder, with pre and post methods for a fixed set of events. Synchronous only.
  • CRM 4.0 plug-ins. A class implementing IPlugin, registered as records in the organization using the SDK’s sample tools. Two custom stages, a parent and a child pipeline, synchronous or asynchronous, and loop detection.
  • CRM 2011 plug-ins. The same idea with a new Execute signature, the parent and child pipelines merged into numbered stages, and a sandbox that let plug-ins run in CRM Online.

Upgrade support stepped down one version at a time. CRM 4.0 still ran 3.0 callouts, with changed behaviour. CRM 2011 ran 4.0 plug-ins but not 3.0 callouts. CRM 2013 stopped running 4.0 plug-ins.

This page draws on Microsoft’s CRM 3.0, 4.0 and 2011 SDKs, its archived CRM 2013 documentation, and current Dataverse documentation. Each section names its sources.

Side by side

Sources: the CRM 3.0 SDK, the CRM 4.0 SDK, the CRM 2011 SDK, and Microsoft’s current Dataverse plug-in documentation. A dash means this site hasn’t sourced that cell yet, not that the answer is “nothing”.

CRM 3.0 callouts CRM 4.0 plug-ins CRM 2011 plug-ins Dataverse plug-ins
Code Derive from CrmCalloutBase, override one method per event Implement IPlugin.Execute(IPluginExecutionContext) IPlugin with a new Execute signature IPlugin.Execute(IServiceProvider)
Registration Hand-edited callout.config.xml on every server Records created through SDK classes; sample tools shipped as source Records; the Plug-in Registration tool, ready-built from SDK 5.0.13 Plug-in Registration tool, opened with pac tool prt, or Power Platform Tools
Where the assembly lives On disk, in server\bin\assembly Database (recommended) or on disk Database or disk on-premises; database in the sandbox Database, sandbox only
When it runs Pre and post methods on 14 named events Pre-event or post-event stage, in the parent or child pipeline Numbered stages in one pipeline Numbered stages; see event pipeline stages
Synchronous or asynchronous Synchronous only Either Either Either
Stopping the operation Pre-callout returns Stop or Abort Throw InvalidPluginExecutionException from a pre-event plug-in Throw InvalidPluginExecutionException
Configuration Assembly, class, onerror, timeout, pre/post attribute lists Unsecure and secure strings passed to the constructor Unsecure and secure strings passed to the constructor
Instances New instance for every call Cached and reused across threads, so must be stateless Cached and reused, so must be stateless
Loop protection None; the SDK gives design advice Infinite loop detection, carried by a correlation token — (the context properties involved are covered on Depth, ParentContext and CorrelationId)
Runs as CRMAppPool identity; impersonate with CallerId CRMAppPool identity; impersonating user set on the step, or chosen in code The calling user, a user set on the step, or impersonation in code
CRM Online Not applicable Not supported Supported in the sandbox Online only

What changed at each upgrade

CRM 3.0 to 4.0

Source: the CRM 4.0 SDK.

Callouts kept working, but the 4.0 SDK calls them a deprecated model, and some behaviour changed:

  • Plug-ins run first. In any stage, registered plug-ins run before callouts, so a callout’s Stop or Abort can’t prevent them.
  • Stop behaves like Abort, but the user sees a standard error message.
  • onerror is ignored. Exceptions from callouts are always shown.
  • Callout instances are cached and shared across threads. Class-level variables that were safe in 3.0 can now corrupt data.
  • Some state changes raise new messages. Closing a case raises CloseIncident, not a set-state event.
  • Multiple organizations. Callouts are directed to the default organization.
  • No new capabilities. Callouts get no asynchronous execution, database deployment, rich context or infinite loop detection. The SDK advises upgrading any callout you need to change to the 4.0 model.

CRM 4.0 to 2011

Source: the CRM 2011 SDK.

  • 4.0 plug-ins keep running without a rebuild, but can’t use the sandbox or tracing, and are registered with the 4.0 SDK’s tool.
  • 3.0 callouts don’t run at all.
  • The pipelines merged. A 4.0 pre-event step in the parent pipeline corresponds to stage 10, and in the child pipeline to stage 20.
  • Registration is validated. Invalid step and image settings that 4.0 quietly ignored make solution imports fail after the upgrade, so fix them first.
  • To rebuild on the 2011 SDK:
    • IPlugin.Execute has a new signature;
    • CallerOrigin gives way to IsExecutingOffline and IsOfflinePlayback, and IsInTransaction is new;
    • catch FaultException<OrganizationServiceFault>;
    • some messages are replaced, such as AssociateRequest for AssociateEntitiesRequest;
    • assemblies must be signed.

CRM 2011 to 2013, and on to Dataverse

Sources: Microsoft’s archived CRM 2013 documentation, and current Dataverse documentation.

  • CRM 2013 doesn’t run 4.0 plug-ins or custom workflow activities. Anything still on the 4.0 model has to be rewritten against the 2011 interfaces before upgrading. See the CRM 2013 page.
  • Dataverse runs plug-ins only in the sandbox, stored in the database, with a time limit and assemblies up to 16 MB. See the Dataverse page.

Porting an old callout

Sources: the CRM 3.0, 4.0 and 2011 SDKs.

If you inherit a callout, it can’t simply be registered on anything newer than 4.0. Each part of it maps to something in the plug-in model:

In the callout In a plug-in
A callout.config.xml entry of entity and event A registered step: message, entity, stage and mode
prevalue and postvalue attribute lists Pre-image and post-image registered on the step
PreCalloutReturnValue.Abort with errorMessage Throw InvalidPluginExecutionException with the message, from a stage before the core operation
PreCalloutReturnValue.Stop No quiet equivalent; an exception with a clear message
Changing entityXml in a pre-callout Change the target entity in the context before the core operation
Class-level fields None: keep state in the context, because instances are cached
CallerId impersonation from userContext.UserId The step’s run-as user, or impersonation in code
Loop guards such as a flag field or a dedicated user Platform loop detection, plus your own check of the context’s depth
A set-state callout on some entities Check which message 4.0 and later raise, for example CloseIncident
onerror="ignore" Catch the exception inside the plug-in

Three rows are this site’s reading rather than a Microsoft mapping:

  • Stop having no quiet equivalent;
  • the depth check;
  • catching exceptions in place of onerror="ignore".

They follow from the sourced behaviour above, but Microsoft never published a callout-to-plug-in porting table.

Sources

  1. Use plug-ins to extend business processes (Dataverse) Microsoft · · Primary, current docs Microsoft’s plug-in overview for Dataverse: declarative options first, synchronous and asynchronous registration, the alternatives (workflow activities, calculated and rollup columns, custom actions, Service Bus and webhooks, Power Automate), and a hard time limit on plug-in execution.
  2. Write a plug-in (Dataverse) Microsoft · · Primary, current docs Microsoft’s plug-in how-to: Power Platform Tools for Visual Studio and the Power Platform CLI as the modern routes, stateless IPlugin classes because instances are cached, secure and unsecure configuration, the optional generated PluginBase class, and the Web API not being supported inside plug-ins.
  3. Build and package plug-in code (Dataverse) Microsoft · · Primary, current docs Microsoft’s packaging constraints for plug-ins: a 16 MB assembly limit, signing when dependent assemblies aren’t used, the dependent assemblies capability as a NuGet package stored in the PluginPackage table, and no support for ILMerge.
  4. Register a plug-in (Dataverse) Microsoft · · Primary, current docs Microsoft’s plug-in registration guide. Isolation mode and assembly location options apply to on-premises only; for Dataverse always accept Sandbox and Database.
  5. Troubleshoot Dataverse plug-ins Microsoft · · Primary, current docs Microsoft’s plug-in troubleshooting guide, including “Sandbox Worker process crashed” (error code -2147204723) and its four usual causes, and errors due to user privileges inside plug-ins, handled by registering the step to run as a user with the privileges or by impersonation.
  6. Microsoft CRM 3.0 SDK (compiled help, crmsdk3_0.chm, 2007 edition) Microsoft · Primary, archived Private archive: CRM-SDK-Rescue/3.0-SDK/crmsdk3_0.chm Microsoft’s SDK help for CRM 3.0: the Server Programming Guide’s callout model, method signatures, callout.config.xml reference, error handling and tracing, and the CrmService and MetadataService web services at /mscrmservices/2006/, including security, impersonation, DynamicEntity, FetchXML and QueryExpression. The owner’s copy came from a third-party software archive; it is a valid help file whose 6,937 pages all carry Microsoft’s 2007 copyright. Read as documents only, never executed. Quote sparingly and cite; do not republish.
  7. Microsoft Dynamics CRM 4.0 SDK (compiled help, CrmSdk4.chm, version 4.0.13, November 2010) Microsoft · Primary, archived Private archive: CRM-SDK-Rescue/4.0-SDK/sdk/crmsdk4.chm Microsoft's SDK help for CRM 4.0 Update Rollup 13 and CRM Online: plug-in development (IPlugin, the execution context, the unsecure and secure constructor strings), the event execution pipeline and its parent and child pipelines, registration and deployment, impersonation, error handling, offline plug-ins, execution of CRM 3.0 callouts, the 2006 endpoint, and what is new in the 4.0 web services. Extracted without running anything from CrmSdk4.exe, whose Microsoft Authenticode signature is valid and which the Internet Archive captured from download.microsoft.com. All 12,022 pages carry Microsoft's copyright. Quote sparingly and cite; do not republish.
  8. Microsoft Dynamics CRM 2011 SDK (compiled help, CrmSdk2011.chm) Microsoft · Primary, archived Private archive: CRM-SDK-Rescue/2011-SDK_from_desk/SDK/CrmSdk2011.chm Microsoft's own SDK help for the 2011 release, from an owner-held copy. Static reading only; the package is never executed and is not part of this repository. Quote sparingly and cite; do not republish.
  9. Upgrade plug-ins and custom workflow activities (Microsoft Dynamics CRM 2013 SDK, archived) Microsoft · · Primary, archived Microsoft’s archived guidance on moving CRM 4.0-style plug-ins and custom workflow activities to CRM 2013: the changed IPlugin signature, CallerOrigin replaced by IsExecutingOffline and IsOfflinePlayback, IsInTransaction, FaultException<OrganizationServiceFault>, AssociateRequest replacing AssociateEntitiesRequest, signed assemblies, and CodeActivity with the Microsoft.Xrm.Sdk.Workflow namespaces.