Stage of Execution:
Pre-Stage: (synchronous) called before the write to the database.
The main reasons to use a Pre-Stage of Execution are synchronous in nature:
Use the Post-Stage of Execution whenever you don't need to use Pre-Stage.
If you don't want the user to wait for the process to finish and there is no race condition use asynchronous.
Triggering Pipeline:
The triggering pipeline is a little less obvious in nature and has an impact on what functionality that you can use in your plugin.
Parent Pipeline: This is the pipeline that is the most common and there are no restrictions imposed in a parent pipeline.
Child Pipeline: This is the pipeline that causes the most confusion and there are limitations that vary with Stage and Execution Mode.
Sometimes a child pipeline is required to trap the event you need, and sometimes you need to trap both the parent and child pipeline for the same entity, message and stage.
Example: Change the quotenumber in the Pre-Stage for the Create of a Quote.
The quotenumber is a field that the CRM web service will not allow you to change after it is written to the database so you need to use the Pre-Stage and modify the context Entity before the end of the Execute method as shown below.
So far so good. This will work in any Pre-Create pipeline!
You can create a Quote in a few ways.
Since you are an efficient plugin developer and are using the ICrmService and dynamic entities to access CRM data because it is pre-authenticated and fast. You retrieve some information to help create the number.
You register your plugin using the handy plugin registration tool for the Quote entity with the following settings:
You create your Quote from Sales -> Quotes -> New and it works!
However, in many business processes the user will create a Quote from an opportunity so it will inherit opportunityproduct information.
Now you create your quote from Sales -> Opportunities (open an opportunity) -> Quotes -> New Quote and for some reason your plugin did not fire. That is because this quote was created in a child pipeline.
The entire QOI chain also occurs in a child pipeline. If you create an order from a quote or invoice from an order it is happening in a child pipeline. There are other places that this occurs as well like creation of an account or contact from a lead.
If you downloaded the plug-in template for CRM, you have probably seen the following method, which is what you need to use in a child pipeline.
You may find another method called GetCrmProxyUsingEndpointUrlInChildPipeline. It is essentially the same.
There is a comment in the plugin template that doesn't tell the whole story.
What it doesn't mention is that what you are allowed to do with that service depends on what your execution mode is.
Hard Coded Restrictions:
A CrmService running Synchronously in a child pipeline is limited to the following:
Those 4 allowed actions are hard coded by MS whenever the plugin is executed inside a transaction, and it appears that all synchronous child pipeline events occur inside a transaction.
However you can do a query in child pipeline if it is registered as asynchronous.
In review:
Pre-Stage: (synchronous) called before the write to the database.
The main reasons to use a Pre-Stage of Execution are synchronous in nature:
- Modify data before it is written to the database.
- Abort the action being taken
- Server Side Validity checking
Use the Post-Stage of Execution whenever you don't need to use Pre-Stage.
If you don't want the user to wait for the process to finish and there is no race condition use asynchronous.
Triggering Pipeline:
The triggering pipeline is a little less obvious in nature and has an impact on what functionality that you can use in your plugin.
Parent Pipeline: This is the pipeline that is the most common and there are no restrictions imposed in a parent pipeline.
Child Pipeline: This is the pipeline that causes the most confusion and there are limitations that vary with Stage and Execution Mode.
Sometimes a child pipeline is required to trap the event you need, and sometimes you need to trap both the parent and child pipeline for the same entity, message and stage.
Example: Change the quotenumber in the Pre-Stage for the Create of a Quote.
The quotenumber is a field that the CRM web service will not allow you to change after it is written to the database so you need to use the Pre-Stage and modify the context Entity before the end of the Execute method as shown below.
var entity = (DynamicEntity)context.InputParameters.Properties[ParameterName.Target]; // . . . retrieve data to populate number . . . // Set value before it is written to the database if( entity.Properties.Contains(numberField)) { entity.Properties.Remove(numberField); } var prop = new StringProperty(numberField, newNumber); entity.Properties.Add(prop);
You can create a Quote in a few ways.
- Sales -> Quotes -> New
- (open an Account) -> Quotes -> New Quote
- Sales -> Opportunities (open an opportunity) -> Quotes -> New Quote
Since you are an efficient plugin developer and are using the ICrmService and dynamic entities to access CRM data because it is pre-authenticated and fast. You retrieve some information to help create the number.
ICrmService service = context.CreateCrmService(true); retrieved = (RetrieveMultipleResponse)service.Execute(retrieve);
- Create
- Pre Stage
- Synchronous
- Parent Pipeline
You create your Quote from Sales -> Quotes -> New and it works!
However, in many business processes the user will create a Quote from an opportunity so it will inherit opportunityproduct information.
Now you create your quote from Sales -> Opportunities (open an opportunity) -> Quotes -> New Quote and for some reason your plugin did not fire. That is because this quote was created in a child pipeline.
The entire QOI chain also occurs in a child pipeline. If you create an order from a quote or invoice from an order it is happening in a child pipeline. There are other places that this occurs as well like creation of an account or contact from a lead.
You are in a child pipeline, now what ?
The first thing that you might try is to take your existing plugin and register it against the child pipeline, but it won't work. The ICrmService is not available to you in a child pipeline.If you downloaded the plug-in template for CRM, you have probably seen the following method, which is what you need to use in a child pipeline.
/// <summary> /// Creates a CrmService proxy for plug-ins that execute in the child pipeline. /// </summary> /// <param name="context">The execution context that was passed to the plug-ins Execute method.</param> /// <param name="flag">Set to True to use impersontation.</param> /// <returns>A CrmServce instance.</returns> private static CrmService CreateCrmService(IPluginExecutionContext context, Boolean flag) { var authToken = new CrmAuthenticationToken { AuthenticationType = 0, OrganizationName = context.OrganizationName, CallerId = (flag ? context.UserId : context.InitiatingUserId) }; var corToken = new CorrelationToken { CorrelationId = context.CorrelationId, CorrelationUpdatedTime = context.CorrelationUpdatedTime, Depth = context.Depth }; var regkey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\MSCRM", false); var service = new CrmService { CrmAuthenticationTokenValue = authToken, UseDefaultCredentials = true, Url = String.Concat(regkey.GetValue("ServerUrl").ToString(), "/2007/crmservice.asmx"), CorrelationTokenValue = corToken }; return service; }
There is a comment in the plugin template that doesn't tell the whole story.
// For a plug-in running in the child pipeline, use this statement. // CrmService crmService = CreateCrmService(context, true);
Hard Coded Restrictions:
A CrmService running Synchronously in a child pipeline is limited to the following:
- Create
- Delete
- Update
- RetrieveExchangeRate
Those 4 allowed actions are hard coded by MS whenever the plugin is executed inside a transaction, and it appears that all synchronous child pipeline events occur inside a transaction.
However you can do a query in child pipeline if it is registered as asynchronous.
In review:
- Use ICrmService for all parent pipelines when at all possible.
- Use CrmService for child pipelines in asynchronous execution mode.
- There is very limited functionality allowed with CrmService for any plugin registered in a synchronous child pipeline
- Querying CRM data in a plug-in registered as a synchronous Pre Create in a child process is currently very unsupported. (ie. direct SQL access)