A rule says a purchase order cannot be saved with a supplier that is on a blocked list. The rule must apply to users on forms, to integrations calling the Web API, and to bulk imports, and a violating save must leave no partial changes behind. Where should this logic be implemented?
Select an answer to reveal the explanation.
Short Explanation
Think of the event pipeline as a checkpoint before the vault door closes. When your synchronous plug-in throws in the pre-stages, it stops the save for every caller, and nothing gets written. The trap is anything that runs after the commit, because by then the bad row already exists.
Full Explanation
Dataverse runs synchronous plug-ins inside the event pipeline for every message, whatever the source: forms, the Web API, the SDK, imports and flows all pass through the same pipeline. A step registered in PreValidation or PreOperation can inspect the Target and throw an InvalidPluginExecutionException; the platform then cancels the operation, rolls back the transaction and returns the message to the caller, so no partial data is saved. An automated cloud flow runs asynchronously after the row has been committed, so the invalid purchase order exists for a period and downstream processes can act on it before the flow deletes it. An OnSave script runs only for users saving a form and is skipped by API and import traffic. An asynchronous PostOperation plug-in also runs after the commit, outside the original transaction, so its revert is a separate, later change rather than a rollback. Exam caveat: PreValidation runs before the main transaction and suits cheap checks; PreOperation runs inside it, which matters when the check must see related changes in the same transaction. Operational check: register the step, then submit a blocked supplier through a form, the Web API and an import, and confirm all three fail with the same message and leave no row.