CRM 4.0 plug-ins: IPlugin, parent and child pipelines, and registration

How CRM 4.0 plug-ins were written, where they ran in a five-stage pipeline with parent and child pipelines, how they were registered and with what permissions, and what CRM 2011 changed.

Answer first

A CRM 4.0 plug-in is a .NET class that implements IPlugin from Microsoft.Crm.Sdk, with a single Execute(IPluginExecutionContext context) method. Registration moved out of a hand-edited server file and into records in the organization, created through SDK classes. The 4.0 SDK says plug-ins “were known as callouts in Microsoft Dynamics CRM 3.0”.

Where 4.0 plug-ins run:

  • Only two of five pipeline stages are open to custom code: pre-event and post-event, both outside the database transaction.
  • Each stage has a parent pipeline and a child pipeline, and a plug-in is registered for one or both.
  • They can be synchronous or asynchronous, and can run on the server, in Outlook offline, or both.
  • On-premises only. In the last 4.0 SDK (4.0.13, November 2010), CRM Online didn’t support plug-ins, and online customers used workflows instead.

Source for this page: Microsoft’s CRM 4.0 SDK help and samples, the plug-in registration entities on the 4.0 install media, and the CRM 2011 SDK for what changed next.

Writing one

  • Reference Microsoft.Crm.Sdk and Microsoft.Crm.SdkTypeProxy from the SDK’s Bin folder, plus System.Web.Services. One assembly can hold several plug-in classes.
  • Write it stateless. CRM caches plug-in instances, doesn’t call the constructor for every run, and may run the same instance on several threads at once. Per-call state belongs in the context, never in class variables. The rule hasn’t changed since.
  • Two constructor strings. A constructor taking two strings receives the unsecure and secure configuration from the registration.
  • The context carries the request. It holds the primary entity, pre- and post-images, and the request’s input parameters. Its properties are read-only, but the contents of its property bags can be changed. A post-event plug-in sees changes a pre-event plug-in made.
  • Get web service proxies from the context. CreateCrmService and CreateMetadataService supply the right URL and credentials and switch on infinite loop detection. Not in a child pipeline, though: there you create the CrmService yourself, and set its CorrelationTokenValue from the context’s CorrelationId, Depth and CorrelationUpdatedTime to keep loop detection. The Depth and CorrelationId page follows those properties forward.
  • Errors. Throw InvalidPluginExecutionException to show your message to the user. Any exception is written to the server’s Application event log and stops all further processing. From a pre-event plug-in, it also cancels the core operation, the plug-ins that haven’t run yet, and workflows triggered by the same event.
  • Passing data between plug-ins uses the context’s SharedVariables property bag, for example from a pre-event plug-in to a post-event one. Only XML-serializable types belong in it.

The pipeline

The 4.0 SDK describes five stages, of which custom plug-ins can use two:

Stage Name Custom plug-ins
Pre-event BeforeMainOperationOutsideTransaction Yes: before the core operation, before any database transaction starts
Pre-event BeforeMainOperationInsideTransaction No, internal use
Core operation MainOperation No
Post-event AfterMainOperationInsideTransaction No, internal use
Post-event AfterMainOperationOutsideTransaction Yes: after the core operation, generally outside the transaction
  • Privilege checks happen after the pre-event stage. A pre-event plug-in that writes to an external system does so before CRM has validated the user.
  • Synchronous plug-ins run immediately and in order. Asynchronous ones are queued with the Asynchronous Service. Synchronous plug-ins run before workflows registered for the same event.
  • Rank orders plug-ins within a stage.
  • Each organization has its own pipeline. A plug-in meant for several organizations is registered in each.

Parent and child pipelines

  • Web service calls start a parent pipeline. The platform’s own internal calls start child pipelines, which only process Create, Update and Delete. A CompoundUpdateRequest on an order line, for example, runs one child pipeline to update the line and another for the order total. Even a plain CreateRequest for an account can run a child pipeline.
  • Order of execution: the parent’s pre-events, then its core operation. During that, each child runs its own pre-events, core operation and post-events. The parent’s post-events run last.
  • A child pipeline’s context includes the parent context, and InvocationSource tells a plug-in which pipeline it’s in.
  • A child pipeline plug-in can end up inside the transaction. When the parent pipeline has started a database transaction, the child plug-in’s changes join it. An exception then rolls everything back and cancels the parent’s core operation. 4.0 gives a plug-in no way to tell whether it’s in a transaction; CRM 2011 added IsInTransaction.
  • The SDK’s first tip for a plug-in that never fires: register it in the child pipeline instead.

Registering

A registration is a set of records: PluginAssembly, PluginType, SdkMessageProcessingStep, step images and secure configuration. The 4.0 install media defines what a step holds:

  • the message and entity it runs for;
  • its stage, and its rank within the stage;
  • its mode, synchronous or asynchronous;
  • filtering attributes: it runs only if one of them changed;
  • a user to impersonate;
  • unsecure and secure configuration for the constructor;
  • whether it runs in the parent pipeline, the child pipeline or both;
  • whether it runs on the server, the Outlook client, or both.

The tools were samples. The 4.0 SDK shipped two registration tools as source code, and called them example solutions:

  • PluginRegistration, a graphical tool. You built it in Visual Studio 2008 after adding web references to the 2007 CrmService, discovery and metadata services.
  • PluginDeveloper, a console tool that used the higher-level RegisterSolution message.

You could also write your own registration code with the same classes. The CRM 2011 SDK says the tool shipped ready-built from SDK version 5.0.13; before that, you built it from source. The 4.0 sample tools didn’t support impersonation, so plug-ins registered with them made web service calls as the calling user.

Storage. Assemblies could be stored in the database, which Microsoft strongly recommended because it’s distributed to every server automatically, or on disk. On-disk storage used the same server\bin\assembly folder as CRM 3.0 callouts, existed for callout backward compatibility and Visual Studio 2005 debugging, and required copying the DLL to each server before registering.

Practicalities from the SDK:

  • Referenced assemblies go in the global assembly cache on every server. If you get assembly load errors, register the plug-in first, then add the references to the cache, then reset IIS.
  • Stop the Asynchronous Service before unregistering an asynchronous plug-in, or a queued job may find its assembly gone.
  • Registering needs membership of the Deployment Administrators group plus the organization-wide create privileges on plug-in assemblies, plug-in types, steps, step images and secure configuration, which System Administrator and System Customizer have. Without Deployment Administrators, registration fails with Not have enough privilege to complete Create operation for an Sdk entity.
  • Registrations weren’t validated. The CRM 2011 SDK says 4.0 accepted invalid step and image settings and ignored them at run time, which surfaces as failed solution imports after upgrading. See the CRM 4.0 page.

Impersonation

  • Plug-ins run as the CRMAppPool identity, Network Service by default. If that identity changes, the new account must be added to PrivUserGroup.
  • A step can name a user to impersonate. Left empty, calls run as the calling user or the built-in “system” user, depending on the request.
  • context.UserId tells you who that is.
    • With no impersonating user registered, it’s the initiating user or “system”.
    • With one registered, it’s that user.
    • When the platform itself started the pipeline, it’s “system”.
  • CreateCrmService(true) acts as UserId; CreateCrmService(false) acts as “system”. That’s a high-privilege account with some restrictions, and the SDK’s example is that it can’t create a task. CreateCrmService(context.InitiatingUserId) acts as the user who made the original call.
  • Offline, impersonation isn’t supported, and records a plug-in creates belong to the logged-on user.

Offline plug-ins

A plug-in can be registered to run online, offline in Outlook, or both. IsExecutingInOfflineMode says which. A plug-in registered for both can run twice: once offline, and again when Outlook synchronizes. Checking whether CallerOrigin is an OfflineOrigin identifies the replay.

CRM 3.0 callouts on CRM 4.0

4.0 still ran 3.0 callouts, with different behaviour and no loop detection. The callouts page lists the differences, and callouts to plug-ins compares callouts, 4.0, 2011 and Dataverse plug-ins side by side.

What CRM 2011 changed

Source: the CRM 2011 SDK.

  • IPlugin.Execute got a new signature, with a different way to reach the context and the organization service.
  • The parent and child pipelines merged into one. A 4.0 pre-event step in the parent pipeline corresponds to stage 10, and in the child pipeline to stage 20. See event pipeline stages.
  • CallerOrigin was replaced by IsExecutingOffline and IsOfflinePlayback, and IsInTransaction was added.
  • Assemblies had to be signed, and registrations were validated.
  • 4.0 plug-ins kept running without a rebuild, but couldn’t use the sandbox and still had to be registered with the 4.0 SDK’s tool.

Sources

  1. 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.
  2. Microsoft Dynamics CRM 4.0 SDK sample code and tool source Microsoft · Primary, archived Private archive: CRM-SDK-Rescue/4.0-SDK/sdk (server, client, tools) Microsoft's sample code from the CRM 4.0 SDK, including the source of the PluginRegistration and PluginDeveloper sample tools and plug-in samples. Extracted without binaries; read only, never built or run.
  3. Microsoft Dynamics CRM 4.0 SDK message metadata exports Microsoft · Primary, archived Private archive: CRM-SDK-Rescue/FromServerISOs/CRM-4.0/SdkMessage*.xml SdkMessage, SdkMessageFilter, SdkMessageProcessingStep, step image and request/response field definitions taken from Microsoft install media. The most direct evidence available here for the 4.0 event pipeline, which the design package lists as a known gap.
  4. 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.