Domain 5 β€” Module 1 of 9 11%
15 of 26 overall
Domain 5: Extend the Platform Free ⏱ ~14 min read

The Plug-in Pipeline: How Dataverse Processes Events

Understand the engine behind every Dataverse operation. Learn the event execution pipeline stages, the execution context, and how Pre/Post Images give your plug-in a before-and-after view of data.

The pipeline that powers Dataverse

Simple explanation

Think of the Dataverse pipeline like an airport security checkpoint.

When you fly, you go through multiple stages: ticket check (are you even allowed here?), security screening (pre-check before you enter the secure area), and boarding (the main action). After boarding, there is a post-departure check (update the passenger manifest).

Every Dataverse operation (create a record, update a field, delete a row) passes through a similar pipeline with four stages. Your plug-in code can intercept the operation at any stage β€” to validate data before it is saved, modify it during processing, or trigger actions after the save completes.

Understanding these stages is the single most important concept for PL-400 Domain 5.

The four pipeline stages

StageWhen It RunsTransaction?Can Cancel Operation?Best For
Pre-validation (Stage 10)Before security checksNo β€” outside transactionYesLight validation, early rejection
Pre-operation (Stage 20)After security, before DB writeYes β€” inside transactionYesModify data before save, complex validation
Main operation (Stage 30)The actual database operationYes β€” the core transactionN/A (system only)Cannot register plug-ins here
Post-operation (Stage 40)After the DB writeYes β€” still inside transactionYes (rolls back entire transaction)Create related records, trigger integrations

Synchronous vs asynchronous execution

ModeRuns WhenUser ExperienceUse For
SynchronousImmediately, blocks the operationUser waitsValidation, data modification, must-run logic
AsynchronousAfter the transaction commits, in backgroundUser continues workingNotifications, logging, non-critical processing
Exam tip: The stage selection pattern

The exam will describe a scenario and ask which stage is correct. Use this decision tree:

  1. Need to reject invalid data before security checks run? β†’ Pre-validation
  2. Need to modify or enrich data before it is saved? β†’ Pre-operation
  3. Need to create related records or trigger integrations after save? β†’ Post-operation (sync)
  4. Need to send notifications or log events without blocking the user? β†’ Post-operation (async)

Red flag: If an answer says β€œregister on the Main operation stage” β€” it is always wrong. You cannot register plug-ins on Stage 30.

The execution context

Every plug-in receives an IPluginExecutionContext that tells you everything about the current operation:

public class ShipmentValidator : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Get the execution context
        IPluginExecutionContext context = (IPluginExecutionContext)
            serviceProvider.GetService(typeof(IPluginExecutionContext));
        
        // What operation triggered this plug-in?
        string messageName = context.MessageName;  // "Create", "Update", "Delete"
        
        // What entity is being affected?
        string entityName = context.PrimaryEntityName;  // "shipment"
        
        // What stage are we in?
        int stage = context.Stage;  // 10, 20, 30, or 40
        
        // Who triggered the operation?
        Guid userId = context.UserId;           // The calling user
        Guid initiatingUserId = context.InitiatingUserId;  // Original user (even through impersonation)
        
        // What data is being sent? (for Create/Update)
        Entity target = (Entity)context.InputParameters["Target"];
        string destination = target.GetAttributeValue<string>("destination");
        
        // What depth are we at? (prevents infinite loops)
        int depth = context.Depth;  // 1 = original, 2+ = triggered by another plug-in
    }
}

Key context properties

PropertyWhat It Tells You
MessageNameThe operation: Create, Update, Delete, Retrieve, etc.
PrimaryEntityNameThe table being affected
StageWhich pipeline stage (10, 20, 30, 40)
UserIdThe user executing the operation (may be impersonated)
InitiatingUserIdThe original user who started the chain
InputParameters[β€œTarget”]The record being created/updated (Entity object)
DepthRecursion depth (check to prevent infinite loops)
PreEntityImagesSnapshot of the record BEFORE the operation
PostEntityImagesSnapshot of the record AFTER the operation

Pre Images and Post Images

Images are snapshots of a record at specific points in the pipeline.

Images give your plug-in a before-and-after view β€” register only the fields you need
FeaturePre ImagePost Image
ShowsRecord values BEFORE the operationRecord values AFTER the operation
Available inPre-validation, Pre-operation, Post-operationPost-operation only
Useful forComparing old vs new values, checking what changedVerifying final state, accessing calculated fields
ContainsFields you registered for in the image definitionFields you registered for in the image definition
On CreateNot available (no previous state)Available in post-operation
On DeleteAvailable (record exists before delete)Not available (record is gone)

Using images to detect changes

// In a Post-operation Update plug-in
Entity preImage = context.PreEntityImages["preImage"];
Entity postImage = context.PostEntityImages["postImage"];

// statuscode is an OptionSetValue, not a string
int oldStatus = preImage.GetAttributeValue<OptionSetValue>("statuscode")?.Value ?? -1;
int newStatus = postImage.GetAttributeValue<OptionSetValue>("statuscode")?.Value ?? -1;

if (oldStatus != newStatus)
{
    // Status changed β€” trigger notification
    tracingService.Trace($"Status changed from {oldStatus} to {newStatus}");
}
Scenario: Kai uses images to track shipment changes

Kai registers a Post-operation Update plug-in on the Shipment table at LogiFlow. He configures:

  • Pre Image: includes status, destination, priority fields
  • Post Image: includes status, destination, priority fields

When a shipment’s status changes from β€œIn Transit” to β€œDelivered”, the plug-in compares the pre and post images, sees the status change, and creates a Delivery Confirmation record with the delivery timestamp.

Why images instead of Target? The Target entity in an Update only contains the fields that were actually changed. If Kai needs to check the destination (which was not changed in this update), it would not be in Target β€” but it IS in the Pre Image.

Question

What are the four stages of the Dataverse event execution pipeline?

Click or press Enter to reveal answer

Answer

Pre-validation (Stage 10, outside transaction), Pre-operation (Stage 20, inside transaction), Main operation (Stage 30, the database write β€” no plug-ins allowed), Post-operation (Stage 40, inside transaction). Plug-ins can register on stages 10, 20, and 40.

Click to flip back

Question

What is the difference between context.UserId and context.InitiatingUserId?

Click or press Enter to reveal answer

Answer

UserId is the identity executing the current operation (may be impersonated by a plug-in or flow). InitiatingUserId is the original user who started the entire operation chain. Use InitiatingUserId when you need to know who really triggered the action, regardless of impersonation.

Click to flip back

Question

Why is context.Depth important in plug-in development?

Click or press Enter to reveal answer

Answer

Depth tracks recursion β€” if your plug-in triggers another operation that triggers the same plug-in, Depth increments. Check Depth to prevent infinite loops: if (context.Depth > 1) return; Without this check, a plug-in that updates its own entity can loop forever.

Click to flip back

Question

Why would you use a Pre Image instead of reading the Target entity?

Click or press Enter to reveal answer

Answer

The Target entity only contains fields that were actually modified in the current operation. If you need to read a field that was NOT changed (e.g., checking the record's owner during a status update), it will not be in Target. Pre Images contain whatever fields you registered for, regardless of whether they changed.

Click to flip back

Knowledge Check

A developer needs to validate that a Shipment record's weight does not exceed 1000kg BEFORE security checks run. If the weight exceeds the limit, the operation should be cancelled immediately. Which pipeline stage should the plug-in be registered on?

Knowledge Check

A plug-in registered on Post-operation Update needs to check whether the Priority field changed. The developer reads context.InputParameters['Target'] but Priority is not in the Target entity. Why?

Next up: Writing Plug-ins β€” implementing business logic with the Organisation Service, performance optimisation, and plug-in registration.