πŸ”’ Guided

Pre-launch preview. Authorised access only.

Incorrect code

Guided by A Guide to Cloud
Explore AB-900 AI-901
Guided PL-400 Domain 5
Domain 5 β€” Module 2 of 9 22%
16 of 26 overall

PL-400 Study Guide

Domain 1: Create a Technical Design

  • Solution Architecture: What Goes Where Free
  • Security by Design: Auth, Roles & DLP Free
  • Designing UX Components: Canvas, PCF & Client Scripts Free
  • Designing Platform Extensions: Connectors, Plug-ins & APIs Free
  • Integration & Automation Blueprints Free

Domain 2: Build Power Platform Solutions

  • Environment Setup & Security Troubleshooting
  • Solutions & Layers: ALM Foundations
  • CI/CD Pipelines for Power Platform

Domain 3: Implement Power Apps Improvements

  • Advanced Power Fx & Canvas Components
  • Troubleshoot & Optimise Apps

Domain 4: Extend the User Experience

  • Client Scripting: Form Events & the Client API
  • Commands, Buttons & Custom Page Navigation
  • PCF Components: Build & Lifecycle
  • PCF Components: Package, Deploy & Advanced Features

Domain 5: Extend the Platform

  • The Plug-in Pipeline: How Dataverse Processes Events Free
  • Writing Plug-ins: Business Logic, Service & Registration
  • Custom APIs & Business Events
  • Custom Connectors: OpenAPI & Authentication
  • Custom Connectors: Azure, Policies & Code
  • Dataverse APIs: Web API & Organisation Service
  • Azure Functions for Power Platform
  • Cloud Flows: Dataverse Triggers & Expressions
  • Cloud Flows: Security, Errors & Child Flows

Domain 6: Develop Integrations

  • Publishing Dataverse Events
  • Service Endpoints: Webhooks, Service Bus & Event Hub
  • Data Sync: Change Tracking, Alternate Keys & Upsert

PL-400 Study Guide

Domain 1: Create a Technical Design

  • Solution Architecture: What Goes Where Free
  • Security by Design: Auth, Roles & DLP Free
  • Designing UX Components: Canvas, PCF & Client Scripts Free
  • Designing Platform Extensions: Connectors, Plug-ins & APIs Free
  • Integration & Automation Blueprints Free

Domain 2: Build Power Platform Solutions

  • Environment Setup & Security Troubleshooting
  • Solutions & Layers: ALM Foundations
  • CI/CD Pipelines for Power Platform

Domain 3: Implement Power Apps Improvements

  • Advanced Power Fx & Canvas Components
  • Troubleshoot & Optimise Apps

Domain 4: Extend the User Experience

  • Client Scripting: Form Events & the Client API
  • Commands, Buttons & Custom Page Navigation
  • PCF Components: Build & Lifecycle
  • PCF Components: Package, Deploy & Advanced Features

Domain 5: Extend the Platform

  • The Plug-in Pipeline: How Dataverse Processes Events Free
  • Writing Plug-ins: Business Logic, Service & Registration
  • Custom APIs & Business Events
  • Custom Connectors: OpenAPI & Authentication
  • Custom Connectors: Azure, Policies & Code
  • Dataverse APIs: Web API & Organisation Service
  • Azure Functions for Power Platform
  • Cloud Flows: Dataverse Triggers & Expressions
  • Cloud Flows: Security, Errors & Child Flows

Domain 6: Develop Integrations

  • Publishing Dataverse Events
  • Service Endpoints: Webhooks, Service Bus & Event Hub
  • Data Sync: Change Tracking, Alternate Keys & Upsert
Domain 5: Extend the Platform Premium ⏱ ~15 min read

Writing Plug-ins: Business Logic, Service & Registration

Write production-quality Dataverse plug-ins in C#. Learn to use the Organisation Service for CRUD operations, optimise performance, and register plug-ins with the Plug-in Registration Tool.

Building real plug-ins

β˜• Simple explanation

Think of a plug-in as a quality inspector on a factory line.

As each product passes through, the inspector checks it (validation), stamps it with a batch number (data enrichment), and records the inspection (audit logging). If the product fails inspection, the inspector stops the line (throws an exception).

Your Dataverse plug-in does the same for data: it uses the Organisation Service to read, create, update, and delete records. It uses tracing to log what it is doing. And it must be fast β€” synchronous plug-ins block the user, so every millisecond counts.

Production plug-ins use the IOrganizationService to perform Dataverse operations (CRUD, execute requests, query data). The service is obtained from the service provider and runs in the security context of the calling user (or a configured system user).

Performance is critical: synchronous plug-ins have a 2-minute timeout, and slow plug-ins degrade user experience. Best practices include minimising queries, avoiding loops with individual operations (use ExecuteMultiple), and leveraging tracing for diagnostics without console.log.

The Plug-in Registration Tool (PRT) is used to register assemblies, steps (which message/entity/stage), and images (Pre/Post) in Dataverse.

Using the Organisation Service

The Organisation Service is your plug-in’s gateway to Dataverse data:

public class ShipmentProcessor : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Get services
        var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        var service = serviceFactory.CreateOrganizationService(context.UserId);
        var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
        
        // Get the target entity (being created/updated)
        Entity target = (Entity)context.InputParameters["Target"];
        tracingService.Trace("Processing shipment: " + target.Id);
        
        // READ β€” retrieve a related record
        Entity account = service.Retrieve("account", 
            target.GetAttributeValue<EntityReference>("customerid").Id,
            new ColumnSet("name", "creditlimit"));
        
        // VALIDATE β€” check business rules
        decimal creditLimit = account.GetAttributeValue<Money>("creditlimit")?.Value ?? 0;
        decimal shipmentValue = target.GetAttributeValue<Money>("totalvalue")?.Value ?? 0;
        
        if (shipmentValue > creditLimit)
        {
            throw new InvalidPluginExecutionException(
                $"Shipment value ({shipmentValue:C}) exceeds customer credit limit ({creditLimit:C}).");
        }
        
        // ENRICH β€” add calculated data to the target before save
        target["estimateddelivery"] = DateTime.UtcNow.AddDays(3);
        target["processedby"] = context.UserId.ToString();
        
        // CREATE β€” a related audit record
        Entity auditRecord = new Entity("shipment_audit");
        auditRecord["shipmentid"] = new EntityReference("shipment", target.Id);
        auditRecord["action"] = "Created";
        auditRecord["timestamp"] = DateTime.UtcNow;
        service.Create(auditRecord);
        
        tracingService.Trace("Shipment processing complete.");
    }
}

Common Organisation Service operations

OperationMethodExample
Createservice.Create(entity)Create an audit log record
Retrieveservice.Retrieve(name, id, columns)Load a related account
Updateservice.Update(entity)Update a field on another record
Deleteservice.Delete(name, id)Remove a temporary record
RetrieveMultipleservice.RetrieveMultiple(query)Query records with FetchXML or QueryExpression
Executeservice.Execute(request)Run specialised requests (Assign, SetState, etc.)

Performance optimisation

PracticeWhyBad ExampleGood Example
Minimise queriesEach query = network round-trip3 separate Retrieve callsOne RetrieveMultiple with filter
Use ColumnSet wiselyLoading all columns is slownew ColumnSet(true) β€” all columnsnew ColumnSet("name", "email") β€” only needed
Avoid loops with individual operationsN creates = N round-tripsforeach with service.Create()ExecuteMultipleRequest for batch
Check DepthPrevent infinite recursionNo depth checkif (context.Depth > 2) return;
Use tracing, not exceptions for loggingExceptions are expensivethrow for non-critical warningstracingService.Trace() for diagnostics
Keep synchronous plug-ins fast2-minute timeout, blocks userCall external API synchronouslyMove external calls to async plug-in or Azure Function
πŸ’‘ Exam tip: Keep plug-ins lean β€” no batch requests

If your plug-in needs to create, update, or delete multiple records, keep each operation direct and focused. Do not use ExecuteMultipleRequest inside plug-ins β€” Microsoft explicitly advises against batch request types in plug-in/workflow code because they add overhead within the pipeline transaction.

Instead, keep plug-ins lean:

  • Limit the number of service calls (aim for under 5)
  • If you need to process many records, move that work to an Azure Function or an asynchronous pattern (post-operation async plug-in, queue, external processor)
  • For external clients (console apps, integrations), ExecuteMultipleRequest IS recommended β€” just not inside plug-ins

The exam may present a slow plug-in scenario. The correct fix is usually: reduce the number of operations, move heavy work out of the plug-in, or switch to async execution.

Plug-in Registration Tool (PRT)

The PRT registers your compiled plug-in assembly in Dataverse and configures when it fires.

Registration steps

  1. Register Assembly β€” Upload the compiled DLL to Dataverse
  2. Register Step β€” Configure the message (Create, Update), entity (shipment), stage (Pre/Post), and execution mode (sync/async)
  3. Register Image β€” Configure Pre/Post images with specific attributes

Step configuration

SettingOptionsImpact
MessageCreate, Update, Delete, Retrieve, etc.Which operation triggers the plug-in
Primary EntityAny Dataverse tableWhich table the plug-in monitors
StagePre-validation, Pre-operation, Post-operationWhen in the pipeline it runs
Execution ModeSynchronous, AsynchronousBlocks the user or runs in background
Filtering AttributesSpecific columns (Update only)Only trigger when these fields change
Execution OrderNumber (1, 2, 3…)Order when multiple plug-ins fire on the same step
πŸ’‘ Filtering attributes save performance

For Update messages, always set filtering attributes. Without them, the plug-in fires on EVERY update β€” even if the user only changed the Description field and your plug-in only cares about Status.

With filtering attributes set to β€œstatuscode”, the plug-in only fires when Status changes. This dramatically reduces unnecessary executions and improves overall system performance.

Question

How do you throw a user-friendly error from a plug-in?

Click or press Enter to reveal answer

Answer

Throw an InvalidPluginExecutionException with a clear message: throw new InvalidPluginExecutionException('Shipment value exceeds credit limit.'). This displays the message to the user in the app. Regular exceptions show a generic error. NEVER use InvalidPluginExecutionException for logging β€” use ITracingService.Trace() instead.

Click to flip back

Question

What is the 2-minute rule for synchronous plug-ins?

Click or press Enter to reveal answer

Answer

Synchronous plug-ins have a 2-minute execution timeout. If your plug-in takes longer than 2 minutes, Dataverse cancels it and rolls back the transaction. This is why synchronous plug-ins must be fast β€” no external API calls, no large batch operations, minimal queries.

Click to flip back

Question

What are filtering attributes on a plug-in step?

Click or press Enter to reveal answer

Answer

Filtering attributes (Update message only) specify which columns trigger the plug-in. Without them, the plug-in fires on every update to the entity. With filtering set to 'statuscode, priority', it only fires when those specific fields change. Always set them for Update steps.

Click to flip back

Knowledge Check

Kai's synchronous plug-in creates 50 audit records when a shipment is processed. It works but takes 30 seconds, frustrating users. What is the most effective approach?

🎬 Video coming soon

Next up: Custom APIs & Business Events β€” creating reusable Dataverse endpoints and configuring event publishing.

← Previous

The Plug-in Pipeline: How Dataverse Processes Events

Next β†’

Custom APIs & Business Events

Guided

I learn, I simplify, I share.

A Guide to Cloud YouTube Feedback

© 2026 Sutheesh. All rights reserved.

Guided is an independent study resource and is not affiliated with, endorsed by, or officially connected to Microsoft. Microsoft, Azure, and related trademarks are property of Microsoft Corporation. Always verify information against Microsoft Learn.