Rediger

Del via


Understand the execution context

The Event Execution Pipeline passes registered plug-ins a wealth of data about the current operation being processed and your custom code's execution environment. The following sections describe the data that is passed to your plug-in or custom workflow activity.

Access execution context for plug-ins

With plug-ins, access this data in your code by setting a variable that implements the IPluginExecutionContext interface:

// Obtain the execution context from the service provider.  
IPluginExecutionContext context = (IPluginExecutionContext)
    serviceProvider.GetService(typeof(IPluginExecutionContext));

This IPluginExecutionContext provides some information about the Stage that the plug-in is registered for, as well as information about the ParentContext.

More information: ParentContext

Access execution context for custom workflow activities

With custom workflow activities, access this data in your code by setting a variable that implements the IWorkflowContext interface:

// Obtain the execution context using the GetExtension method.  
protected override void Execute(CodeActivityContext context)
{
 IWorkflowContext workflowContext = context.GetExtension<IWorkflowContext>();
...

This IWorkflowContext provides some information about the workflow that the custom workflow activity is running within.

Property Description
ParentContext Gets the parent context. See ParentContext
StageName Gets the stage information of the process instance.
WorkflowCategory Gets the process category information of the process instance: Is it a workflow or dialog (deprecated).
WorkflowMode Indicates how the workflow is to be executed. 0 = asynchronous, 1 = synchronous

ParentContext

The ParentContext provides information about any operation that triggers the plug-in or custom workflow activity to run.

Except for specific documented cases, avoid taking a dependency on values that you find in the ParentContext to apply your business logic. The specific order in which operations occur isn't guaranteed and might change over time.

If you choose to take a dependency on values found in the ParentContext, take steps to ensure that your code is resilient to adapt to potential changes. Test the logic regularly to verify that the conditions you depend on remain in effect over time.

ExecutionContext

The IExecutionContext interface provides the rest of the information. The IPluginExecutionContext and IWorkflowContext classes implement this interface.

For plug-ins, all the properties of this execution context class provide useful information you might need to access in your code.

Note

For custom workflow activities, you generally don't use these properties.

Two of the most important properties are the InputParameters and OutputParameters properties.

Other frequently used properties are SharedVariables, PreEntityImages, and PostEntityImages.

Tip

A good way to visualize the data that is passed into the execution context is to install the Plug-in Profiler solution that's available as part of the Plug-in Registration tool. The profiler captures the context information as well as information that allows for replaying event locally so you can debug. Within the Plug-in Registration tool, you can download an XML document with all the data from the event that triggered the workflow. For more information, see View plug-in profile data.

ParameterCollections

All the properties of the execution context are read-only. But the InputParameters, OutputParameters, and SharedVariables are ParameterCollection values. You can change the behavior of the operation by modifying the values of the items in these collections, depending on the stage in the event execution pipeline your plug-in is registered for.

The ParameterCollection values are defined as KeyValuePair structures. To access a property, you need to know the name of the property that the message exposes. For example, to access the Entity property that's passed as part of the CreateRequest, you need to know that the name of that property is Target. Then you can access this value by using code like this:

var entity = (Entity)context.InputParameters["Target"];

Use the Microsoft.Xrm.Sdk.Messages and Microsoft.Crm.Sdk.Messages documentation to learn the names of the messages defined in the SDK assemblies. For custom actions, refer to the names of the parameters defined in the system.

InputParameters

The InputParameters represent the value of the OrganizationRequest.Parameters property that represents the operation coming in from the web services.

As described in Use messages with the SDK for .NET, all operations that occur in the system are ultimately instances of the OrganizationRequest class that the IOrganizationService.Execute method processes.

As described in Event Framework, operations go through a series of stages. You can register your plug-in on stages that occur before the data is written to the database. Within the PreValidation and PreOperation stages, you can read and change the values of the InputParameters so that you can control the expected outcome of the data operation.

If you find that the values in the InputParameters collection represent a condition that you can't allow, throw an InvalidPluginExecutionException (preferably in the PreValidation stage) that cancels the operation and displays an error to the user by using a synchronous plug-in, or logs the error if the plug-in is asynchronous. For more information, see Cancelling an operation.

OutputParameters

The OutputParameters represent the value of the OrganizationResponse.Results property that represents the return value of the operation. Each of the message response classes that are derived from OrganizationResponse contain specific properties. To access these properties, use the key value that is usually the same as the name of the properties in the response class. However, this isn't always true. The following table lists the message response class properties that have keys different from the name of the properties.

Response Class Property Key Value
BackgroundSendEmailResponse EntityCollection BusinessEntityCollection
CloneContractResponse Entity BusinessEntity
CloneMobileOfflineProfileResponse CloneMobileOfflineProfile EntityReference
CloneProductResponse ClonedProduct EntityReference
ConvertSalesOrderToInvoiceResponse Entity BusinessEntity
CreateKnowledgeArticleTranslationResponse CreateKnowledgeArticleTranslation EntityReference
CreateKnowledgeArticleVersionResponse CreateKnowledgeArticleVersion EntityReference
GenerateQuoteFromOpportunityResponse Entity BusinessEntity
GetDefaultPriceLevelResponse PriceLevels BusinessEntityCollection
RetrieveResponse Entity BusinessEntity
RetrieveMultipleResponse EntityCollection BusinessEntityCollection
RetrievePersonalWallResponse EntityCollection BusinessEntityCollection
RetrieveRecordWallResponse EntityCollection BusinessEntityCollection
RetrieveUnpublishedResponse Entity BusinessEntity
RetrieveUnpublishedMultipleResponse EntityCollection BusinessEntityCollection
RetrieveUserQueuesResponse EntityCollection BusinessEntityCollection

The system doesn't populate the OutputParameters until after the database transaction, so they're only available for plug-ins registered in the PostOperation stage. If you want to change the values returned by the operation, you can modify them within the OutputParameters.

Shared variables

Use the SharedVariables property to pass data from the API or a plug-in to a step that occurs later in the execution pipeline. Because this property is a ParameterCollection value, plug-ins can add, read, or modify properties to share data with subsequent steps.

The following example shows how to pass a PrimaryContact value from a plug-in registered for a PreOperation step to a PostOperation step.

public class PreOperation : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Obtain the execution context from the service provider.
        Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
            serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

        // Create or retrieve some data that will be needed by the post event
        // plug-in. You could run a query, create an entity, or perform a calculation.
        //In this sample, the data to be passed to the post plug-in is
        // represented by a GUID.
        Guid contact = new Guid("{74882D5C-381A-4863-A5B9-B8604615C2D0}");

        // Pass the data to the post event plug-in in an execution context shared
        // variable named PrimaryContact.
        context.SharedVariables.Add("PrimaryContact", (Object)contact.ToString());
    }
}

public class PostOperation : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Obtain the execution context from the service provider.
        Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
            serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

        // Obtain the contact from the execution context shared variables.
        if (context.SharedVariables.Contains("PrimaryContact"))
        {
            Guid contact =
                new Guid((string)context.SharedVariables["PrimaryContact"]);

            // Do something with the contact.
        }
    }
}

Important

You must add serializable data to the shared variables collection. Otherwise, the server doesn't know how to serialize the data and plug-in execution fails.

Note

For a plug-in registered for the PreOperation or PostOperation stages to access the shared variables from a plug-in registered for the PreValidation stage that executes on Create, Update, Delete, or by a RetrieveExchangeRateRequest, you must access the ParentContext.SharedVariables collection. For all other cases, IPluginExecutionContext.SharedVariables contains the collection.

Passing a shared variable from the API

To introduce a shared variable when you call an API, use the keyword tag from either the Web API or the SDK for .NET to pass a string value.

You can access this value in the Shared Variable collection by using the tag key. Once set, you can't change this value.

For more information, see Add a shared variable to the plugin execution context.

Entity images

When you register a step for a plug-in that includes a table as one of the parameters, you can specify that a copy of the table data be included as a snapshot or image by using the PreEntityImages and PostEntityImages properties.

This data provides a comparison point for table data as it flows through the event pipeline. Using these images provides much better performance than including code in a plug-in to retrieve a table just to compare the attribute values.

When you define an entity image, you specify an entity alias value you can use to access the specific image. For example, if you define a pre-entity image with the alias 'a', you can use the following code to access the name attribute value.

var oldAccountName = (string)context.PreEntityImages["a"]["name"];

More information:

See also

Event Framework
Write a plug-in