CRM 4.0 enhanced the concept of plug-ins (called callouts in earlier versions). Plug-in’s are now supported on lot of messages. Plug-in model is actually a 1:1 mapping of Messages and Requests. In order to automate the business logic through a plug-in you need to find the right Message to be registered for the plug-in. For example, to extend the logic on “Create of an entity”, you need to register the plug-in on Create Message.
I have tried to answer lot of questions in the form of FAQ for plug-in development and registration. You can refer to my previous blog for more information on the plug-in registration tool.
1. How do I find the right Message for registering my plug-in?
· An action in CRM can be performed using different SDK operations. So in order to find the correct subset of messages, you need to filter the messages by entity. Then you can register the plug-in on all the messages that look closer to the functionality.
· To make the search easier, I created an excel sheet with all valid list of Messages and Entities for plug-ins which is located at http://code.msdn.microsoft.com/crmplugin. Filter the list by the entity name to find the correct subset of messages.
2. Why do I need to register on SetState and SetStateDynamicEntity separately?
· As I mentioned earlier there are multiple messages that perform the same action in CRM. One such example is SetStateRequest and SetStateDyanmicEntityRequest . If you want to write a plug-in on SetState, then you need to register it on both messages.
3. Why does Opportunity State change not caught when I register on SetState alone?
· This is one more example of multiple SDK operations valid for an action in CRM. If you look at the Opportunity entity, you shall find that there are Lose, Win, Setstate, SetStateDynamicEntity requests that change the State of an opportunity. So you need to register your plug-in on all the mentioned messages.
4. Why did my plug-in not fire on Create Account, when Opportunity is converted to Account?
· In CRM 3.0 we had this problem. So, If you want your plug-in to be fired when an action happens as a result of another action, you need to register the plug-in in the Child pipeline. Plug-in Registration tool allows you to specify this option during the Step registration process.
· If you register the plug-in with InvocationSource=Parent, then it is fired only on the primary action
5. How do I pass configuration data to plug-in? I don’t see support for app.config
· Hard coding connections, customer configuration in plug-in is always a bad idea. So if you need some information, either you had to read from Registry or from a File. Multi Server deployment is major problem in either of these cases. So wouldn’t it be nice if CRM provided some functionality to store the configuration data to the plug-in just like it stores the assemblies in database? Well, you have it in the form of SdkMessageProcessingStep.configuration and SecureConfiguration properties. Both of these properties are strings. They can be set when registering the Step and their values are available in the plug-in constructor at runtime.
· SdkMessageProcessingStep is an OrgOwned entity, so any user in CRM can read the values from this entity via SDK. So data stored in it is not restricted to administrators only.
· On the other hand, SecureConfiguration can only be read by CRM Administrators. So if you want to store username, pass word information, etc., save it in this property.
· For a sample look at SamplePlugins.LogContextToCRM in the downloads section
6. How to read the IPluginExecutionContext.InputParameters Property bag and what is the structure?
· InputParamaters property is a serialized version of the SDK Request operation
· Microsoft CRM SDK has good explanation about this property http://msdn2.microsoft.com/en-us/library/cc151087.aspx
7. I need to get an Image of the entity when the update requested is fired
· Register a PreImage on the Step
· Context.PreImages[“entityalias”] should have the DynamicEntity
8. I would like to be notified when IncidentResolution entity is created. I also needed information about the related incident entity. How do I get this information?
· IncidentResolution entity is created as part of Resolve Incident request. So, you can only catch this event if you register on Child pipeline for Create of IncidentResolution entity. You can parse the incidentid from the InputParameters property bag
· However if you need to read custom attributes or other attributes on the incident, you have to call CRM. Since it is a child pipeline, we restrict you in calling CRM by not providing the Proxy. You can work this around by creating a proxy by yourself.
· PluginHelper. GetCrmProxyUsingEndpointUrlInChildPipeline in the downloads section has sample
9. How to get the EntityId in the Plug-in?
· I have created a PluginHelper.cs available in the download section, which helps you understand how to retrieve the entityId based on the message. You can extend it for other messages too. In short you need to look at the Request and see where the entityId is available and then retrieve it accordingly in the plug-in.
· Look at the RetrieveEntityId plug-in in the downloads section.
10. Can I look at what is in the IPluginExecutionContext without debugging?
· IPluginExecutionContext has lot of properties and most of them are dictionaries. I understand that it is hard for developers to know what its contents are before enumerating or debugging. So I created a plug-in that serializes the IPluginExecutionContext and writes it back to CRM so that you can view the Xml in the Form.
· SamplePlugins.LogContextToCRM Plug-in in the download section creates the serialized Xml into the new_pluginContext custom entity. Once you register the plug-in on any message, you shall get the Context in the custom entity
11. How do I know if my plug-in is running in Outlook Offline mode or on the Server?
· You can use IPluginExecutionContext.IsExecutingInOfflineMode property
· SamplePlugins.AmIExecutingOffline plug-in in the download section demos the scenario
12. How do I know if the Request originated in the Outlook Offline mode and replayed?
· You can use CallerOrigin property
· SamplePlugins.OfflinePlaybackConflictResolution plug-in in the download section demos the scenario. It rejects all the updates on the entity from the Outlook Offline client, if the Server had an updated version of the same entity.
· SamplePlugins.MyPluginCallerOrigin plug-in also demos the scenario
13. What is Depth and CorrelationId in the IPluginExecutionContext?
· Depth is an integer property that we automatically increment when Plug-in makes a call back to CRM using web service. When the Depth reaches certain max value, we treat it as potential infinite loop and reject the call.
· CorrelationId is a Guid that is set on the initial call to CRM and used later for tracking resultant calls.
· When you use CreateCrmService() method in the plug-in, we set these values on the proxy. However, if you create your own proxy, please copy these values so that the tracking is in place. PluginHelper.GetCrmProxyUsingEndpointUrlInChildPipeline in the download section has the sample code.
· We do recommend you to use our proxy so that we take care of all the minute details.
14. I registered my plug-in in Child pipeline and I can no longer create proxy to connect to CRM
· We disabled this feature since it is very easy to get into infinite loops as you are way low in the pipeline.
· But if you do have the scenario and absolutely need it, then you can create your own proxy. I have demonstrated this in the PluginHelper.GetCrmProxyUsingEndpointUrlInChildPipeline method but use with Caution !!!
15. What is the difference between InitiatingUserId and UserId in IPluginExecutionContext?
· You registred the plug-in to impersonate as UserA. If UserB makes a call to CRM which triggers the plug-in, then you get UserA in the UserId property and UserB in the IntiatingUserId property.
Contents of the Download
Sample Plug-ins that demonstrates usage of the Context variables can be downloaded from http://code.msdn.microsoft.com/crmpluginsamples. I have included the PluginContext.Xml which has the new_plugincontext custom entity. SampleSolution.Xml has all the registration steps to demo the scenario. Please log your comments and suggestions on the download site so that they are in sync with the new releases for samples.
· LogContextToCRM plug-in logs all the Context to new_plugincontext entity
· AmIExecutingOffline plug-in displays a popup showing if plug-in is running in Offline or on the Server
· RetrieveEntityId retrieves the EntityId from the InputParameters property bag
· RetrieveIncidentIdOnCloseIncident gets the IncidentId from the InputParameters property bag
· PluginHelper.cs has all the libraries to help write plugins easier