At RSM, we prioritize the use of out of the box features of Microsoft Dynamics CRM to solve business problems. We also take advantage of the vast Dynamics CRM marketplace of Independent Software Vendors (ISVs) where applicable. We do this for a number of reasons but primarily because it is easier for the client to maintain, has faster delivery and is easier on upgrades. When we need to go beyond the system capabilities, we utilize custom development via plugins, workflows and external web applications and services. If you find yourself headed down the custom path, I have compiled a few tips you can use to get the most out of your code base. If you have any additional ones to add, please leave a comment.
Use a Shared Library for Common Functionality – This might sound like a no brainer but let’s talk more specifically about what we should go inside of a shared library.
- Proxy Classes and Helper Classes Sample – If you are using the early bound types in Dynamics CRM, go ahead and put in the proxy classes generated from the CrmSvcUtil. This consolidates their access to one place and if you need to make an update, you can go ahead and re-generate the new proxy classes and update a single project. If you are using late bound types and will be accessing similar fields from multiple contexts, take advantage of the HelperClasses.cs file in the Software Development Kit (SDK) samples under samplecodecsprocesscustomworkflowactivitytestnet4lateboundactivity. The sample uses public static classes and public constant string variables to consistently call the string value for Entity Names, and can be extended via your own custom classes to consistently call attributes. If you ever need to update or add a field it can be done in one place.
- Extension Methods – Extension methods are a powerful way of extending the behavior of classes you may or may not own. In particular, adding extension methods to the Entity class can be very useful to consolidate similar code into one method and make it convenient to call. While there is a lot of debate about whether they are good or bad, I find they can be very useful in consolidating code and make it more readable. If you’re unsure, here is a great read on StackOverflow about when to use and not to use extension methods. Along with this great power, I feel obliged to include a word of caution here. Once another developer adds the Extension classes’ namespace to their file, all of the extension methods will be available. Keep the most generic ones in a ProjectName.Extensions namespace and add new namespaces if the extension methods apply to a more specific context.
- Use linked classes instead of using ILMerge or deploying assemblies – Visual Studio offers a great feature where you can link classes from one project into another. Rather than deploying other dependent assemblies directly to the Dynamics CRM server, it is often possible to use linked classes to bring in custom code from another project in your solution. This helps reduce the complexity of the deployment and there won’t be any gotchas if you ever move servers. If you have pre-compiled assemblies that you don’t own, you can certainly use the a tool called ILMerge. I recommend installing the tool using Chocolatey, as it will assist in configuring it in your machine’s path and keeping it up to date. If your team utilizes Chocolatey to install ILMerge then you can add a post-build command to merge the assemblies into one file, making for easy plugin deployment.
- Use Base Classes – We are using an Object Oriented language, so let’s take advantage of the features! Specifically in Dynamics CRM, I recommend the following base classes.
- Server Context – There is an intersection of functionality between a Plugin and Workflow in Dynamics CRM. The shared components are the ITracingService and IOrganizationService. The intersection of functionality can be abstracted into an interface called the IExecutionContext. This interface can be used to provide a unified data access layer. The interface has the potential to unify your login and server access functions across all custom development. Use constructor injection in your implementation of a data access layer. The constructor should contain an IExecutionContext parameter so implementation details can be swapped out. If you write a repository layer which accepts these, it can be taken advantage of from a plugin, workflow or external application context.
- Local Plugin Context -This class should inherit from your ServerContext discussed above and implement the parts specific to a plugin’s execution context such as the IPluginExecutionContext. I recommend using a lot of the code which is included in the Dynamics CRM Plugin Template in Visual Studio. When creating a project using the Dynamics CRM Plugin template, the template will add a LocalPluginContext class file. There are a lot of goodies in here which you can reuse but I would first make it a full-fledged class in your project rather than internal to the plugin assembly.
- Local Workflow Context – Should implement the components specific to the workflow context such as the IWorkflowContext.
- Base Plugin & Base Workflow – These base classes will be inherited from all of your custom plugins and workflow. The BasePlugin base class can take advantage of the LocalPluginContext class via an internal reference and use it for all data access and writing to the ITracingService interface. If you have a custom logging implantation, initialize it and make it available here. Remember, this class will be used for all plugins so keep things generic but helpful. A few things to consider doing here are:
- Retrieving pre- and post-entity images
- Reading the secure/insecure configuration
- Registering your plugin events and validating the context before invoking them (see the Tuple code in the LocalPluginContext class)
- The BaseWorkflow will perform similar capabilities as the BasePlugin taking advantage of the LocalWorkflowContext, I think you get the concepts from the plugin example so I won’t flesh out any details here.
Microsoft CRM Software Development Kit (SDK) References
When working on a project, there is nothing worse than having a brand new project from source control fail to build. It is even worse when it is caused by missing references. Local copies of SDK assemblies could be extracted to any path on each developer’s machine. Do not check-in projects with SDK References to local files.
There are two approaches I have seen used to resolve this issue. Either include the assemblies in a folder relative to the solution that is included in source control or use a package manager such as NuGet. With NuGet, you get some additional dependency tracking and versioning but does require the developer to install the packages the first time they get the solution.
If you’re looking for some assistance customizing Microsoft Dynamics CRM, RSM can help. We are a full service technology partner including a full range of Dynamics CRM services from implementation, optimization and support, as well as application development and customization services. Contact our professionals for more information on our services at 855.437.7202 or crm@rsmus.com.
By: Luke Grindahl – Minnesota Microsoft Dynamics CRM partner