Plugin pre and post images explained
What entity images are, which ones are available for each message and stage, and how to use them to compare old and new values in a plugin.
What you'll learn
- Why Target isn't enough on Update
- Which images exist for each message and stage
- Register an image with only the columns you need
- Compare old and new values safely
On this page
On an Update, the Target entity only contains the columns that changed. If your logic needs the value before the change — or a column that didn't change — you need entity images.
Pre and post images
- A pre-image is a snapshot of the record before the operation.
- A post-image is a snapshot after the operation.
You register them on a plugin step and choose which columns they include.
What's available where
| Message | Pre-image | Post-image |
|---|---|---|
| Create | No | Yes (post-operation only) |
| Update | Yes | Yes (post-operation only) |
| Delete | Yes | No |
Register the image
In the Plugin Registration Tool, select your Update step and choose Register New Image:
- Image type: Pre Image
- Name and Entity Alias:
PreImage(you'll use the alias in code) - Parameters: select only the columns you need, for example
statuscodeandownerid
Selecting all attributes works, but it makes every update heavier. Pick only what you use.
Use it in code
This plugin blocks reopening a case that was already Resolved:
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (!context.PreEntityImages.TryGetValue("PreImage", out Entity pre)) return;
var target = (Entity)context.InputParameters["Target"];
if (!target.Contains("statuscode")) return;
var oldStatus = pre.GetAttributeValue<OptionSetValue>("statuscode")?.Value;
var newStatus = target.GetAttributeValue<OptionSetValue>("statuscode")?.Value;
const int Resolved = 5;
if (oldStatus == Resolved && newStatus != Resolved)
{
throw new InvalidPluginExecutionException("Resolved cases can't be reopened. Create a new case instead.");
}
}A handy merge pattern
When you need the full picture after an update, combine the pre-image with the changed values from Target:
var current = new Entity(pre.LogicalName, pre.Id);
foreach (var attr in pre.Attributes) current[attr.Key] = attr.Value;
foreach (var attr in target.Attributes) current[attr.Key] = attr.Value; // changes winThis avoids an extra Retrieve call — faster and fewer API requests.