Developing Plug-ins for CRM 4.0


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

Thank you

Ajith Gande

Comments (42)

  1. Philippe says:

    What message do i use if i want to execute my plugin when an associated entity (in case of N-N relationship) is added. The update message does not work on this one.

    thanx

  2. Ajith Gande says:

    Hi

    AssociateEntities Message is used to associate 2 entities when a N-M relationship is created on them. This message is not Valid for Plugins. So you cannot catch this event in the Parent pipeline.

    Since the intermediate object that gets creates is not a first class entity in CRM, you cannot register Create Message on them.

    Sorry, you cannot catch the operation for those reasons.

  3. Ajith Gande says:

    Associate Entities Message is not valid for Plugins. Update will not catch the Event when the entities are associated. So Plugins cannot be used for catching this operation in CRM.

  4. mthulisi says:

    I want to write a plugin that fires when a new quote is created.The plugin is supposed to run through a piece of code and then return with a qoute number from a folder in the file server.The quote number is supposed to update the quote number field.Previously in CRM 3 we were using Xml to do this.How can i do it in  CRM 4.0?

  5. Ajith Gande says:

    In CRM 4.0 the Xml is in the form of a DynamicEntity just like the quotedetail entity. You need to update the DyanamicEntity to achieve this functionality.

    Context.InputParameters is a property bag that has the input request. Get the DynamicEntity from it as mentioned in the Blog and the samples. After that update the dynamic entity in PreCallout.

    Thanks

    Ajith

  6. mthulisi says:

    How do you make web service calls to CRM when you register a plugin in a child pipeline?All  i want to do is to retrieve the user details from CRM.

    Thanks

    Mthulisi

  7. Kristoffer says:

    Hi.

    I have a plugin that sets the email.to property to a certain address if you have set a ‘send as SMS’-flag on the form. Which messages do I need to register the plugin on to cover all send email scenarios? I have manage to get it to work on ‘normal send’ but not on quick campaign email sends… Right now it’s registered on the post create email. If I get it to work I promise to share the code 

    Regards

    /Kristoffer

  8. Ajith says:

    Hi

    We do not recommend contatcing CRM in Child pipeline but if it is a must you can do using the code i mentioned in the PluginHelper.cs in the download. (Create your own proxy)

    LogContextToCRM plugin demontrates the feature.

    Thanks

    Ajith

  9. SyraJohn says:

    I’m writing my first plug-in for CRM 4.0.  I’m trying to target the Account class and I’m attempting to update the AccountNumber property.  I’ve followed the SDK sample code and I’m making sure that the context’s Target property is an Account (entity.Name = EntityName.account.ToString).

    Can I update the property of the context’s target or do I have to use ICrmService to retrieve an account object?

    Would this code work (entity is a local DynamicEntity and set to the context’s Target property) :

    If entity.Properties.Contains("accountnumber") Then entity.Properties("accountnumber") = "ALFKI"

    I’ve used the PlugIn Registration Tool and my plugin shows up in the tool.  However, I’m not getting any feedback and it’s not working.  I’ve tried registering it to Pre Stage and Post Stage but neither results in the AccountNumber field getting set to the value in my code.

    Any thoughts or links are appreciated.  I’m not sure how to debug this code.

  10. AD says:

    Hey,

    I am developing a plugin that will trigger on the setstateDynamicentity. How can I get the entity ID.

    the target parameter does not seem to work???

  11. emily says:

    does anyone know how to insert a ‘group’ into the cc’ field, when mass emailing?

  12. Rich says:

    I am trying to re-use some 3.0 code where I got the pre and post XML.  I thought using the preimage and postimage would get me that but it is empty.  I used your tool to register the plug in and I see all of the existing properties in the target part of the inputparamters.  Am I out of luck????

    Thanks,

    Rich

  13. Ajith Gande says:

    Hi

    Look at the PluginHelper.cs which has the deatils on getting the entity id.

    Thanks

    Ajith

  14. Ajith Gande says:

    Hi

    Regarding Setting the AccoutnNumber. Register the Plugin on PreCreate. Now get the InputParameters Property bag and update the account number. If you created the account without AccountNumber then you need to add the AccountNumber to the property bag. Once you update the InputParamters it would be created.

    DynamicEntity accountEntity = (DynamicEntity)context.InutParamters["Target"];

    accoutnEntity.Properties.Add(new CrmNumber("accountnumber",1));

    Try using the new_PluginContext  and LogPluginContext plugin to know what is being passed in the plugin.

    Thanks

    Ajith

  15. Ajith Gande says:

    Hi

    In CRM 4.0 , you need to use Context.PreImages and Context.PostImages property bags. They have Images that registred as. Look at the samples in the download

    Thanks

    Ajith

  16. Nick says:

    Thanks Ajith, your plugin samples were very helpful and answered my questions perfectly!

    Keep up the good work!

  17. vinaykotagiri says:

    Hi

    I have a Custom Entity in CRM 4.0 named abc_MarketingDownload.

    Can i create a Plug-in on Post Create Message for this Custom Entity.

    Thanks

    vinay

  18. Ajith says:

    Viney

    yes you could create Post Create on this entity. Plugin Registration tool shall list this custom entity in the Primary Entity List on the step registration form.

    Thanks

    Ajith

  19. Ben says:

    – Kristoffer,

    Have you tried using the email ‘Send’ message.

    I’ve used it to modify an email just prior to it being sent from CRM and it works fine, although I’m having problems using it on emails generated from a campaign activity, so if anyone has any suggestions…

    Thanks,

    Ben.

  20. AjithG says:

    Hi Ben/ Kristoffer

    You can listen to the calls made by CampaignActivity by listening to the Child Pipeline of Email Create. Well, you might not be interested in the Create since you want to do special logic only on the Send. Since Campaign activity creates these e-mails, you can check for the parentContext.MessageName =ProcessOneMemberBulkOperation and then process the business logic on the e-mail being created.

    You can always hook up same logic to Send so that it is covered when people update the e-mail and click Send from the UI.

  21. Ludi says:

    Hi

    How can a plugin to execute in within the CRM database transaction,for example,when create a account i need to check SAP ERP if this account have already exist.if not,cancel the create.

    thanks!

  22. Chandima says:

    Hi Ajith ,

    I am developing a plugin to change the Status of Opportunity entity once it converts to the Quote entity.

    I found that plugin doesn’t fire when I register it on Post OnCreate method of the Quote.

    Simply I want to chnge the statuscode to "Quoted" of Opportunity when it creates Quote.

    Could you help please….

  23. Robert says:

    i am trying to develop a plugin that updates an account. The issue is I also have a retrieve and a field is being updated in the retrieve. Is there any way i can know where the call came from… ie if its a true retrieve ie opening a form or from an update?

  24. Pradeep says:

    How to abort the Plug-In Execution in middle?

  25. Rudy says:

    How can i register a plugin on a many to may relationship. I have account n:n brands, and when i add a new account_brand, i need to know this. Can someone help me ?

  26. Uma Maheswari Anbazhagan [MSFT] says:

    Hi Robert,

    I am a little confused as to whether you are trying to register the plugin on update or retrieve. Can you please provide more details on your scenario?

  27. Uma Maheswari Anbazhagan [MSFT] says:

    Hi Chandima,

    If the plugin is registered on parent pipeline of Create Quote, it will not be trigerred since creating a quote from opportunity internally uses a different message than create quote. Register it on the child pipleine of create quote and it should work.

  28. Uma Maheswari Anbazhagan [MSFT] says:

    Hi Pradeep,

    To abort the Plug-In Execution in middle:

    1) If you have a plugin registered on some event/message (say account create), and if you don’t want the plugin to execute while the account is created, you need to disable the plugin.

    2) If you want the plugin to be trigerred and but abort it while the plugin is being executed, you can throw exception from plugin code.

    2) If you want the plugin that doesn’t throw any exception, to be trigerred and but need to abort it while the plugin is being executed, there is actually no way to it if the plugin is registered in synchronous mode. If it is an asynchronous plugin, you can go to system jobs and try to cancel it. But its tricky and can be done only if the aysnc job has not completed already.

    I would like to know your scenario to provide better guidance.

  29. Peter says:

    Hi,

    I am closing an opportunity and changing its status as “Won”, and on the status as “Won”, I want to create a new record in custom entity by using the properties of Opportunity.

    The problem is that I am not able to get any pre or post entity image in Win Step. So, if I do not have any image, then no properties and hence I am unable to create record in custom entity.

    Do let me know how can we get any image there or to get the properties of Opportunity?

    Thanks

    Peter

  30. Krutika Suchak says:

    Hi,

    To register a plug- in, a user should be a part of deployment admin group right?

    I want the list of users who has been added in deployment administrators group. Is it possible through webservice? If so what request should be made to retrieve it?

    Thanks,

    Krutika

  31. krutika.suchak says:

    Hi,

    To register a plug- in, a user should be a part of deployment admin group right?

    I want the list of users who has been added in deployment administrators group. Is it possible through webservice? If so what request should be made to retrieve it?

    Thanks,

    Krutika

  32. I’m trying to call a third party web service from within my plugin but it keeps saying it can’t find the Endpoint.

    As there is not going to be a config file available for it to read I’ve saved them as string variables.

    Now how do I pass that data to the call?  I’ve looked at the override methods when I call the service esp. Binding, Address but it still doesn’t find the endpoint.

  33. Naga says:

    I am trying to get the parent entityid while creating a child entity.

    Here is my post: http://social.microsoft.com/Forums/en/crmdevelopment/thread/fdbdb5bf-c856-4d83-a166-fc624b893a9e

    could you please let me know your comments?

    Thanks

  34. Cory Bonallo says:

    Hey Kristoffer, did you get your code working?  You promised to share it if you did.  I have exactly that business requirement that I need to address.  I would really appreciate a copy of the code!  Thanks!

    Cory

    coryb@jensenonline.com

  35. Raj says:

    I've a custom entity.

    When Deactive the record : i've below conditions

      -> IF Condition True -> Deactive

      -> Else do not deactive.

    I set the primary entity = custom entity

    message – > SetStateDynamicEntity

    Even when condition if false, the record is getting deactive after showing the error message.

    Please let me know where im going wrong.

  36. Mohit says:

    Thanks for wonderful FAQs.. I have a query on one of that..

    "As I mentioned earlier there are multiple messages that perform the same action in CRM. One such example is SetStateRequest and SetStateDyanmicEntityRequest"..

    Can you please tell me which message perform the same action as "CREATE".

  37. Rakhi says:

    Am beginner

    I want to create generic plugin which executes when an entity is updated.A system note should be generated with the information about changs made in the record i.e. updated fird should be stored as a note for that record.

    Please do help…

  38. updating the attributes in related custom entities using MS CRM 4.0 Plugin says:

    Hi Folks,

    Here is my question:

    I have created three custom entities, the Custom entity2 is the primary entity which the updating has to occure. The CE2 has 1:N relationship with CE1 and CE3. In CE2 I have an attribute by the name attrib_BalanceAmount. * If I update the attrib_BalanceAmount value in CE2, then the related entities CE1 / CE3's Total Amount should update automatically.

    *please share your information/code to update the attributes in all custome entities.

    Thanks,

  39. I HAVE DEVELOPED CUSTOM PLUG-IN FOR FILE UPLOADING AND RICH TEXT BOX FOR CRM 2011 USING XRM REFERENCES…. BOTH ARE FULLY GENERIC AND CAN BE USED IN ANY FORMS OF CRM 2011

  40. It’s difficult to find educated people for this subject, however, you seem like you know what
    you’re talking about! Thanks

Skip to main content