If you are relatively familiar with the developer toolkit and have it installed and working you might appreciate a more step by step guide on how to get a plugin setup. If not this post below goes into more detail around getting the toolkit installed and deploying your first plugin.
This screenshots shown in this guide are based on VS2012 and the last stable release of the developer toolkit with CRM 2013. At time of writing the toolkit works with 2016 Update 1 along with Dynamics 365. It is worth mentioning that you don’t need the developer toolkit to create a plugin however using the latter does save time especially when working on a real client project. If you need help on installing the developer toolkit and setting up your development environment I have wrote separate guides outlining how to do it.
For now we will assume you are new to plugins and are wanting to learn how to get this working using the CRM developer toolkit. By the end of this article you will have created a simple plugin and got more familiar with the supporting tools. If you already familiar with the developer toolkit you may want to skip ahead towards the end when we get into some actual plugin code.
From within Visual studio:
Go to new Project (you have a few options here for creating plugins)
- Use the Solution template for Dynamics CRM (See below)
- Use the Dynamics CRM Plugin Library extension method
- Create new CRM Package which will automatically add a Plugin class for you
- Just create an empty C# class project that implements IPlugin
For the purposes of this guide just select the template. Before you click on the OK ensure you have set the target .NET framework.
Annoying bug: Even if you select the right target framework above, the actual target framework in the projects it creates does not match. This means you have to go and update each of the projects (Plugins/Workflows) to correct target version. One way round this is to do the above once update the references etc and then save this as your own custom VS template.
Pay attention to the bottom right “Create directory for solution”, ensure your paths are correct typically you want things structured as follows:
Your Solution Folder
- Packages (contains stuff like ILMerge/NUGet libs)
- Bin Folder (CRM SDK’s and 3rd party DLL’s)
- Silverlight etc
Personally I like to remove the Silverlight project as that is a deprecated technology and not relevant to most CRM projects. Next thing which should happen if your developer toolkit is working properly is for Visual Studio to prompt you for the CRM Dynamics tenant and login credentials.
As it says under Connection Details, it wants the “discovery service API” details. Under the hood it will be using the SOAP end point https://disco.crm4.dynamics.com/XRMServices/2011/Discovery.svc and the Organisation SOAP end point once you have selected the Organisation and solution name.
The important thing of course is the username and password, as that tells the toolkit what our target tenant is which itself may have multiple instances (organisations) each having their own specific solutions this is why the toolkit uses the discovery API for the CRM Explorer panel/deployment. Now click Ok then it will go and create a CRM solution for you consisting of:
- CRM Package project (contains final assemblies for CRM deployment/Web resources)
- Plugin project C# class library
- Workflow project C# class library
- Silverlight project (you can delete this as abandoned by MS, 2014 due to HTML5)
However we are not yet ready for development or deployment:
- Framework version for the projects are likely to be incorrect
- Framework warnings due to VS Toolkit being built in 4.5 not targetted at 4.5.2
- The namespaces and assembly names in your solution wont be fit for purpose
- No project exists yet to contain your early bound classes
- No ILMerge (Online CRM needs it to reference non CRM/MS system DLL’s in Plugins)
- The plugin and workflow projects have to be strongly signed before deployment
- The CRM references are likely to be pointing at a location outside of the solution (not ideal) what we want to is copy those locally within the solution Bin folder
Depending on your experience the above may be self explanatory and easy for you to get up and running so you can skip the next part. However, the rest of this guide will assume this is not the case and will give you step by step help to address the stuff listed above.
The important thing if you are new to this is to just break things down into layers and focus on one project area at a time, rather than trying to get the whole thing building and working straight away.
CRM Explorer Pane
Once you create a CRM Solution via the developer toolkit extension, you will see a CRM explorer pane allowing you to browse components that “exist in your CRM Solution”, if you close this pane or need to get to it in future simply go to Tools Menu->Connect to Dynamics CRM Server or View->CRM Explorer.
However: If this is a new project I recommend you try to connect first as without that you will have no connection to CRM for deployment. I have blogged how to get the CRM Explorer/Connection window back.
The CRM explorer pane is loaded every time you open the Solution in VS and is needed so you can control the target CRM instance for the intended deployment.
You can remove the silverlight application project. Also note as of 2014, Silverlight is no longer recommended for Dynamics CRM as Microsoft dropped it in favour of HTML 5.
Create a folder called Bin within the route of your solution. Now copy the CRM SDK DLL’s from its Bin folder into that folder. Update all references in the CRM Solution to point at this location. The only exception is if you have SvcUtil sourcecode added and its not latest version as that needs to use the DLL versions as shipped. Ensure copy local is false for the System and Microsoft CRM references.
Update ALL references in the solution and its child projects to point at the same DLL’s in that Bin folder, this will help reduce build errors, keep things packaged together for TFS deployment and help to minimise reference issues especially where multiple developers are downloading and checking in the code to a central repository.
Sign the Plugin and Workflow projects (required before you can deploy to CRM), no password is required in the signin. Use defaults and create separate key files (normally with same name) in both Plugin and workflow projects. If you have Display Adaptor issues just hit CTRL+S to save changes.
Create a folder called “Base Class” within the Plugin project and drag the auto generated Plugin.cs into this location. We don’t edit this file directly, unless wishing to inherit useful global methods in our project. The plugin.cs base class implements IPlugin.
More on Plugin.cs
If you right click on an entity in CRM explorer and create the plugin step that way, it will dynamically, create for you a new class with everything you require from the base class plus update the RegisterFile.crmregister file for you whenever you change the plugin step or namespace within VS.
The default Plugins.cs file created for you automatically should be treated as a base class and then you inherit from it acccordingly this is useful as we can create our standard methods if needed in the base class for enscapsulation which will get inherited by any new plugin clases. Ensure too that the namespace in the file is what you would want to use a default for all of your plugins it should match.
Go to CRM Explorer, right click the entity you want to create a plugin on to automatically generate the class file and empty GUID’s behind the scenes in RegisterFile.crmregister. It will not only create the class for you (based on what you entered in the class name) but also automatically inherit from the base class and change from the default IPlugin to Plugin (the latter being your base class).
The developer toolkit extension uses the base class to “dynamically” create your new plugin class, therefore it wont be identical. Interestingly note that when it creates your class Execute method it takes a parameter of LocalPluginContext (don’t confuse this with the normal standard IServiceProvider parameter that you typically see in Plugins) instead we instantiate our class.
As part of that instantiation it automatically calls the default base constructor which sets up service provider, factory, organisation service for us. If you need to do REST/Execute operations you can easily access them via that class instance, cast them to local new instances or define them locally. However, you should always do operations within the Plugin context itself to ensure you don’t have issues when the same plugin code is being fired under a different worker process, or when you have multiple synchronous threads that are being executed at the same time. The latter can lead to concurrency/data inconsistency issues if you step outside of the context
Understanding the RegisterFile.crmregister file
The file is stored within the CRM Package project and is updated locally by the developer toolkit whenever you use the CRM explorer to create or change Plugins. It contains the plugin step and configuration information along with any custom workflow activities that you may have defined. As well as the assembly information for the Plugin(s) and workflows it defines the IsolationMode, the UID for the step, along with any other custom configuration you may have specified.
Before your first deployment to CRM this file will contain empty GUID’s (36 bytes in length) covering the DLL assemblies to be built within your solution. Then whenever you change the plugins, if you do so via the CRM Explorer and deploy this way, it will automatically publish the configuration within CRM and then retrieve from CRM the specific ID’s and other information.
Though not ideal however sometimes you can (and must) modify this file directly after performing some action in CRM explorer, a good example is that VS Toolkit does not support all of the “message types” you would otherwise see if using the plugin registration tool (e.g. The associate / disassociate messages) which don’t have a primary entity (it is system wide). In this scenario you would create this based on say account then manually edit the file to specify isolation mode, message name etc. In any case you need to tweak the isolation mode for Workflow assembly if you are deploying to an Online (Sandbox) instance.
Right click on CrmPackage and rename to give it a meaning full name (e..g Client Project Name) do the same for the Plugin project and Workflow project ClientName Plugin etc.
In the property window for the plugin projetc ensure the Assembly Namespaces are set properly e.g. Assembly Name=.Plugins and class default namespace = .CRM.Plugins. Ensure target framework is right for the target version of CRM Dynamics. Ensure plugin base class has identical namespace as that used in new plugin classes created via the toolkit otherwise you will get missing assembly errors and unnecessary separate namespace in the packaged DLL between the base class and your classes.
Tip: By renaming the project files this will automatically cause RegisterFile.crmregister file to be updated with the new assembly namespaces so we don’t have to manually edit the file.
If you haven’t already now you can remove /delete the default sliverlight application project.
Now try to Build the Solution.
You are likely to get following error when trying to build the solution.
CRMApiToolkitSolution.Plugins.dll” could not be resolved because it was built against the “.NETFramework,Version=v4.5.2” framework. This is a higher version than the currently targeted framework “.NETFramework,Version=v4.5”.
This is because the target framework for VS Toolkit extension was built using v4.5 not 4.5.2. To fix we have to right click on the CRM package project, unload it, then manually edit the csproj file line
Update it to:
Save and Reload the Project, the warning will disappear. If you ever modify a project file directly I recommended restarting VS as sometimes it can throw off the MSBuild process leading to obscure errors.
At the moment VS toolkit was last released with CRM2013 and still works with 2016. It is believed that MS though they discontinued support will be updating this for 2016 and VS 2015 onwards. Once you know it’s stable it best to move onto 2015 and latest versions of the toolkit.
Before we deploy create an empty class on account entity via CRM explorer as follows:
The values you select and enter in here will be part of the RegisterFile.crmregister file used to register the events/steps within your CRM solution. Check if RegisterFile.crmregister has been updated and that the isolation modes are as you would expect for the target CRM instance. At this point there will be no ID’s within the file as we are yet to deploy to CRM.
If you missed the step earlier, update the new plugin namespace to match the base class accordingly if there is any mismatch. Now Build the Plugin project, then build the entire solution, check all is well with the compilation before trying to deploy.
Deploying to CRM
Once the deployment has successfully completed you can check if RegisterFile.crmregister has been updated. If you get a prompt as follows it’s a good sign that everything has connected and been applied as expected:
We can see from below that the VS extension has retrieved and populated the assembly and step GUID’s following the registration within CRM.
Just to ensure without doubt that everything is connected up right I would recommend you go into CRM and within the solution you deployed to manually check the ID’s and all settings are as you would expect.
You could also go into the default solution and check here as ultimately that is where assemblies reside on the server. Public key token is generated via the signed DLL key and deploy action. Finally, if looking for exact details on how this was registered the number one tool to use is Profile Registration.
Adding more Plugin steps or changing steps
You can do this from CRM Explorer, navigate the CRM Assemblies area, expand the Plugin Assembly and then right click “new step”. Doing it this way especially if you want a plugin to handle multiple messages that fire on entities will ensure that VS is the master.
Now every time you or another developer deploys to CRM it will mirror the VS configuration which always overwrites the data within CRM (even changes that were done using the plugin registration tool for example) or someone builds the DLL in a separate project and manually updates via the profile registration tool.
If the plugins rely on specific “GUIDS” hard-coded it ensures that when you deploy to dev, uat, production instances that by editing the RegisterFile.crmref file directly prior to deployment that everything will work as expected. Hard-coding GUID’s should be avoided where possible but there are some exceptions where this may be the only way to implement the solution due to CRM Dynamics major reliance on GUIDs.
In CRM after VS deployment
Creating early bound classes
It is probably at this stage you will want to think about creating early bound classes. Some people argue that late binding is faster and less of a bloat to CRM. I’m not going to get drawn into the debate between the two approaches other than to say I prefer to be type safe and have better code portability/readability than get caught up over a difference measured in the milliseconds. It all depends on what you are doing in the solution. Read my article here if you need to know how to create early bound classes.
Coding a simple Plugin
Appreciate the above is quite a lot of information to digest!! However it is best to be comprehensive on this because everyone is at a different level of experience.
It may not always be necessary to set this all up every-time you develop a plugin but it’s worth starting here so you have a full picture on how you would typically structure a VS solution for CRM development.
Now you have this full CRM solution setup in VS you can have multiple project types and explore the different server and client facing API’s available to you under the SDK all from one solution (I think that’s nice!).
Here is some code, for a simple plugin, it will following the creation of an Account record, create for us a basic task record in CRM that is associated to the account.
This simple plugin uses both Late Binding and Early Binding techniques. It should be registered as follows:
- Post Operation
- Create Message
- Primary Entity: Account
Ok, first thing .. I have deliberately coded the above in such a way that is showcases different key areas of a plugin (it is not the standard way you would typically code it) but for the purposes of helping you to understand the Plugin Anatomy presenting it in this way should help you to understand what is happening at a lower level.
Before we get into the nuances of what this code is actually doing and what the various lines mean lets start at a higher level. There are a few common concepts you need to be aware of when creating plugins or indeed accessing the SOAP endpoint which is something you do whenever you create a Plugin/Custom workflow activity or develop an external application that connects to a CRM organisation.
The CRM SDK’s make life a little easier for you in that it encapsulates the SOAP envelopes and transport levels so you simply call methods most of the time and don’t necessarily need to be concerned with what is happening on the network transport layer. There are a number of “proxy” sevices that can be used across the various interfaces to make coding easier.
This in an interface provided by the CRM SDK. The service provider is the means by which we can instantiate the other services. It is normally the default parameter when creating plugins However, understand that if you create the plugin step via Developer Toolkit the localcontext parameter it is showing in the Execute method is actually a separate base class implementation that gives us easier access to to services without having to mess around creating local context, factory and service objects instead we can access that from the localContext object.
The source which has caused the plugin to execute, from here you can access input parameters such as the name and type of the context. You can also check things like the Message name to ensure that the code is only executing if invoked by the expected message.
We use this to instantiate our organisation service. If getting a service you typically pass in the userId that was part of the context. The Id passed in will depend on how you registered the Plugin, so if you specified “calling user” it will be the user which triggered the event; otherwise the specific user GUID you selected in the pick list.
The desired web service either organisation or discovery. Under the bonnet this will be using the SOAP API. The Web API is for custom web resources only running within the application. This is true to both Plugin/Workflow execution and external applications created that connect to CRM instances. Service is used for Accessing Data and MetaData from the CRM platform.
Keeping it simple we have 3 types:
Changes made here are applied before any database transaction. It is said to execute outside of the CRM transaction.
Changes here are done within the transaction before changes are committed.
Code that runs in here is “after” the event, so in our example, code in here would be expected to execute following the Creation of an Account with the details about that Account being available to us to then do some subsequent post action (like Creating a Task) and setting what it is regarding.
Late Binding Example
Entity incoming = (Entity)_context.InputParameters[“Target”];
Creates a “late bound” entity object based on the context target, which we are expecting here to be “Account”. You can however see in the code I haven’t used late binding and instead used an explicit class type.
Early Binding Example
Task followup = new Task();
Creates an “Early bound” task type object. This means we can access the attributes, using intelli-sense that are known to exist on that entity. This means we are “type safe” and don’t have to second guess what reference or primitive types are required at any given time. In more complex coding scenario’s having access to that early information on the objects we are working on is crucial to avoid errors and to improve productivity during development.
Calling the Organisation Service
We are using the CRUD operation known as Create and passing in the early bound type. This will then go and create for us a Task record in CRM that is correctly set to regarding the target account. Underneath the SDK libraries are building SOAP envelopes and Executing them on the server. The ToEntity conversion is massively important without it the code will not work in Sandbox mode when using early bound classes that are within a different assembly that has been merged unless you have taken key steps to ensure that proxy types are included in the merge process explained here.
And that’s it! Easy peasy lemon squeezy.