CRM Plugin Code Structure – By functionality or by event?

When we work on CRM plugins, there is a key decision at the beginning of the development cycle when it comes to structuring your plugin code. There are two main ways of writing your plugins :  by events or by functionality. In this post, I will describe the two approaches and discuss some of their pros and cons.

Plugins can be described as handlers for events fired by Microsoft Dynamics CRM (source). There can be multiple handlers for single events.  Let’s use an example for the purpose of this post.

For the event, we’ll use the creation of a case (pre operation). We will consider that when  the case is created, there are two actions that need to be performed : generate and assign a unique case number and validate that required fields have authorized values in them.

Plugin structured based on Events

For the plugin structure based on event, it means we’ll have a single plugin registered on the Case Pre create event, and inside the plugin class we’ll have two business logic blocks of code to execute (one to generate the unique number, the validate the required fields).

SNAGHTML4e81484     SNAGHTML4e74f7f

Plugin structured based on Functionality

In this case, we’ll have two plugin classes registered on the same event (again, one plugin for unique number generation and another to validate the required fields) – Sorry, no screen shot here but you get the idea Smile.

Pros and Cons

Functionality Based Plugins

  • Pros
    • Ease to see what plugins does what when looking at Plugin Registration tool (or similar tools) because of more descriptive feature name in plugin name
    • Ability to disable specific features for various scenario (e.g. disable system integration or auto calculation plugins during data migration)
    • Unit Tests can be written against a plugin class to test one functionality
    • Provides the ability to easily write generic plugins and register on multiple events by any power user
  • Cons
    • Large amount of plugin classes
    • Large amount of registered plugin steps; can become big and hard to read/maintain

Event Based Plugins

  • Pros
    • Plugin registration is straight forward and easy to maintain
    • Ease to easily the operations performed at each event when looking at the code
    • Plugin classes are standardized : always tied to an event and single point of entry for all developer to see actions executed on the event
    • Unit tests can be written against specific Business logic methods and/or classes (even independently from the plugin execution context depending on how they are written)
  • Cons
    • Must use alternate mechanism to disable specific features if needed (e.g. configuration data element)
    • Possible timeout if executing multiple large business logic blocs (mind you, if you have a timeout in a plugin – which happens after two minutes, you probably have a design issue)
    • General  dependency to having a developer around
      • Generic business logic code blocks can be written but a developer is required to insert the business logic on additional events
      • To view the all operations performed for an event, a developer needs to look at the code

So which model should you use?

I have used both models heavily on various occasions. For me personally, the decision on which one to use comes down to a project’s needs and a coding style preference. As an example, if you know you’ll have a lot of generic features and want to have reusable plugins, you are better off using the functionality based model. The same applies if you know there are processes that require to disable specific functionality on a regular basic. On the other hand, if you project is relatively small and includes simple business logic on a few events, the event based approach can be a good choice. Feel free to add feedback in the comment section if you see other pros and cons for each of these models or want to share experience in the area.

Exchanging data between CRM Forms and IFRAMEs

One of the most common requirements when we add content in IFRAMEs or Web Resourses in CRM is to have the ability to communicate with the calling or source CRM form to perform all sorts of operation. This article explains how this can be achieved using the postMessage JavaScript messaging mechanism.

What does postMessage do?

It’s a JavaScript method which was initially created to facilitate cross-origin communication between web pages. There are often valid scenario in which we need to display a page from another website in a new window or in an IFRAME. That’s the easy part. The more complicated part is when there is a requirement to perform some operations on the source page based on a action that occurs on the external page in the new window or IFRAME.

In the example below, consider we have a contact form that displays an external page in an IFRAME. When a button in clicked in the IFRAME, information (example, a lookup value) is passed to the CRM form, the value is set on the screen and the form is saved.

Step 1 – Write methods for the CRM Form: Register Listener, Message Handler  

The code below contains two methods, the first one (RegisterListener) sets a method that will be called if the postMessage is invoked (UpdateContactLookup). 


SADAX.Contact =
{
   RegisterListener: function () {

     if (window.addEventListener) {
       window.addEventListener('message', SADAX.Contact.UpdateContactLookup, false);
     }
     else { // IE8 or earlier
       window.attachEvent('onmessage', SADAX.Contact.UpdateContactLookup);
     }
   },

   UpdateContactLookup: function (event) {

     var origin = "";
     if (event.domain) origin = event.domain; // IE
     else if (event.origin) origin = event.origin; // FireFox - Chrome

     if ("https://source" == origin) {

       if (event.data != null) {

         var entity = SadaxJSON.parse(event.data);
         if (entity) {

           var value = new Array();
           value[0] = new Object();
           value[0].id = entity.Id;
           value[0].entityType = entity.LogicalName;

           var lookup = Xrm.Page.getAttribute("sadax_referencecontactid");
           lookup.setValue(value);
Xrm.Page.data.save();
}
}
else
{
alert("This message has been posted by an unknown source ('" + origin + "', expected 'https://source').");
return;
}
} 
}

Step 2 – Register the listener on Form’s OnLoad event

image

Step 3 – Write Code for the IFRAME to post the Message from the IFRAME

After the business logic execution, the postMessage method is called on the parent CRM form as follows:

function SetContactLookup(entityReference)
{
   var entity = {};
   entity.Id = entityReference.id;
   entity.LogicalName = entityReference.entityType;

   window.parent.postMessage(SadaxJSON.stringify(entity), "https://source");
}

Comments / Wrap up

At step 3, using the postMessage on the window.parent will cause the SADAX.Contact.UpdateContactLookup method to be fired on the parent CRM form. Notice that the method receives an event object as a parameter. The content of the object slightly differs based on the browser being used (IE vs rest of the world). Mostly, you should pay attention to the event.domain or event.origin attributes. This is used to validate the website that posted the message is safe (i.e. the one you are expecting).

There is also an event.data attribute that contains parameters that are sent from one page to another. In this case, we are using a renamed JSON library to stringify our custom object types. Passing an object without stringifying it would work, but we found it didn’t work well in all browsers/version. The reason for the renamed JSON library is again browser compatibility reasons. If IE8 is out of scope for you, you probably do not need this.

Notes:

  • This also work for web resources opened in a different window using window.open or Xrm.Utility.openWebResource
  • IE8 doesn’t allow to postMessage to other windows, only to iframes.
  • I haven’t tried this in CRM Online so you can try it by yourself if need be.

Developer Focus – CRM Solution Manager Review

I’ve been using the CRM Solution Manager for a few months now and I thought I’d provide some insights on the product in case you are considering making the investment.

What is it the CRM Solution Manager?

CRM Solution Manager is a productivity tool for CRM Developer that integrates with Visual Studio and Dynamics CRM. The idea is for a CRM developer who writes plugins, custom workflow activities, JavaScript and HTML web resources to be able to do his/her development and manage deployments of the development components to CRM all from Visual Studio in a user friendly way.

The product comes as a Visual Studio Extension file (.vsix) and currently supports Visual Studio 2010, 2012, 2013 and 2015, that means it very likely supports the version you are currently using (I really hope so!). There is a free 30 day trial available to try.

After the installation, when you run Visual Studio, you are presented with a screen to log onto CRM:


When the connection is completed, you can create your projects (Class Libraries for plugins and custom workflow activities, and Empty Web project for web resources). Once your projects are created, the fun can start.

Plugins and Custom Workflow Activities Development

For server side development, the tool brings a lot to the table.

If you have a class library project not linked to CRM or not containing anything at related to CRM, right clicking on the project will give you the possibility to either add the Plugin Assembly to CRM or create Proxy Classes.


For a Plugin Assembly that’s already linked to CRM, you get a menu that give you the ability do a little more:


  • Build and Publish: This will build the Project, and update or publish the Plugin Assembly in your the CRM Organization you are connected to
  • Add Proxy Classes to Project: This will open a window for you to selected the entities you want to generate proxy classes for, as well as other settings such as the path (folder in which you want the classes to be created/updates), and which naming convention you want to use for your entities and fields (Display Names or Schema/Logical names)


  • Edit Plugin Assembly Details: Allows changes to Plugins Assembly details such as Location, Isolation Mode. Also gives the ability to configure ILMerge for merging multiple assembles at build time. This is helpful if you are used to creating ILMerge post-build event all the time.


  • Edit Plugins and Steps: This will give you a screen that looks very similar to the Plugin Registration Tool with options to add plugins, register/edit/disable steps, add and edit plugin images etc. Basically you get the same content as the Plugins Registration Tool directly from Visual Studio


  • Download all linked Items from CRM: This option will force a download of all the items that are linked to CRM. In this case, we are talking about the Proxy Classes that were generated using the feature described above.
  • Update all items: This will update CRM with the content of the project, in this case, it will update the plugin assembly using the latest build

Worth nothing, all the configuration (linked items to CRM, CRM connection etc.) is saved in an Xml file that resides in your solution root folder. If you need and want to carry your CRM Solution Manager configuration across multiple environments and for multiple developers, make sure you include it in your source control (it is not done automatically).

Client-Side (JavaScript/HTML) Development

The experience is very similar with to what we get on the server side. Right clicking on the right button will give you a CRM option with a few options.


  • Add Items to Project: Given that it is a web project in this case, the items that can be added to the project are a bit different than what we had in the Plugin project. You can select a CRM Solution, and from there you can download the Charts, Images, JavaScript, Sitemap, Web Files (HTML), as well as generate JavaScript and TypeScript Intellisense files for selected entities.


  • The other options are similar to what we had in the section above:
    • Downloading all linked items from CRM will update all web resources by getting the latest version from CRM
    • Update all items will update CRM with the items in your Visual Studio project
  • Worth noting, individual web resource files in the VS project are linked to their CRM counterpart which means you can publish single web resources by right clicking on them in the VS project and selecting Publish file to CRM


Wrap-up

The Good

  • The product is really not too intrusive. It doesn’t add any project creation template that your solution becomes dependant on. It doesn’t create any additional cumbersome toolbox that you need to open to manage your CRM related operations (no point intended)
  • It is a HUGE productivity booster. One can easily get used to having proxy classes easily regenerated on demand, as well as JavaScript Intellisence. One can also really get used to deploying web resources and plugin assembly without opening CRM or the plugin registration tool
  • The support team is very reactive, I have received an answer to all my inquiries within a day
  • The product is being actively maintained and updated to support the latest versions of Dynamics CRM and Visual Studio

The Bad

  • If you are using CRM Solution Manager for specific things (e.g. creating Proxy classes and Option Set Enumerators), it means one of two things. Either all of your developers need to be equipped with the add-on in case the classes need to be regenerated  or the entire team dependent on one person to regenerate the entities classes when required. If you are the only developer on the project, it will work well for you. However if you are a consultant and need to hand-off the code when you are done, you may not want to us it to generate the proxy classes as people who will maintain the code might not have it to generate identical classes in the future.
  • The price point is a bit high. At $209.95 US per license (with volume pricing available), it is almost as expensive as some of the excellent and proven productivity tools such as Resharper ($300), Coderush ($250). That makes your development environment a bit expensive to set up. Pricey also considering there are free tools like the CRM Developer Toolkit (for which we are still waiting for a new version for VS2015, CRM 2015/2016), some of the tools in the XRM Toolbox and also the CRM Developer Extension developed by fellow CRM MVP Jason Latimer. The latter is a must try, the feature set is impressive and extremely complete! I haven’t had a chance to work with it yet but I will make sure to review it once I do.

All in all, I would recommend the CRM Solution Manager if you are an Organization with Dynamics CRM deployed internally with multiple developers writing code that targets the platform. If you are a solution integrator or a consulting shop, make sure you don’t create too much of a dependency with the tool, because your clients won’t necessarily have access to the add-on.

Hope this help!

For further questions and assistance with your CRM Development tools and environment, or other Dynamics CRM related inquiry, feel free to reach out to us!

 

Setting up your Dynamics CRM Development & Source Control Environment

Every time I meet people trying to get CRM projects going, I get plenty of questions about how to setup environments and source control properly. Unfortunately, there is no easy answer. However I thought I would share a model that I’ve used on many occasions and that works well with a combination of a defined methodology, appropriate tools, training, commitment and discipline from the project team members. It is mostly relevant for large projects with multiple developers.

The proposed setup is based on the flowchart below, and it is inspired by fellow MVP Gonzalo Ruiz’s article on the same topic.

 

Development machines (CRM DEV)

The development machines can be a developer’s laptop or work station with CRM development tools + a dedicated CRM organization for the developer (CRM Online or on premise). It can also be a full server (or VM) with CRM installed and dedicated to a single developer. These organizations are setup with a master configuration solution (more on this later) and smaller transport solutions to bring required components for development.

Developers use the various development tools to write code and to debug (attach to CRM services, attach to IIS, using Profiler, browsers debugging tools or using tracing).

When development items are completed, developers build temporary “transport solutions” containing the components they worked on and they push them to the Master Configuration organization. Developers must be careful and not make schema changes on their own development organizations. As the code is deployed to the master configuration, it should also be archived in the source control.

Master Configuration CRM Organization

There is only one Master Configuration environment. It contains the schema configuration and all schema changes should be made there. There is usually one or multiple “Master” solutions sitting in this organization based on how you decide to structure your deployments. You may want to have multiple solutions for various types of customizations (e.g. one for schema, one for plugins, one for web resources etc.), or based on functionality grouping.

When developers set up their organizations, they can pull the entire master solutions from the master configuration organization as unmanaged and install them in their development. They can also create temporary “transport solutions” to pull only the customizations they need.

A process (manual or automated) should be put in place to archive the master solutions on a regular basis (daily is recommended). Archiving could be saving the CRM solution files in source control, or even creating snapshots of the server and keep them around for a reasonable period of time.

Integration / Test CRM Organization

This organization receives the master solutions and is used to perform tests. It can be combined with the master configuration environment. The choice to go with a managed or unmanaged solution when going from master configuration to integration/UAT/Prod environment is a business and technical decision. It is a separate discussion that we could write an entire blog post about J.

UAT / PRE PROD / PROD

These environments receive the master solution(s) after they have been tested and validated on the Integration/Test CRM organization.

Wrap Up

Putting this type of environment in place is not easy to do. It takes a lot of process implementation, tools and automation build and more important, training and discipline from the project team members. When working on small project (small number of developer, low amount of customizations and code), going with this approach is overkill. It applies best for big projects when you have multiple developers and heavy customization requirements.

 

This was fun. Hope it helps!

CRM 2013 – Client API: Save Event Arguments

There are a few useful additions that have been added to the client API around the Save event. They are 3 methods that have been formally introduced:

getSaveMode: Returns a value indicating how the save event was initiated by the user.
isDefaultPrevented: Returns a value indicating whether the save event has been canceled because the preventDefault method was used in this event hander or a previous event handler.
preventDefault: Cancels the save operation, but all remaining handlers for the event will still be executed.

The key method is the getSaveMode function. Think about the new auto-save feature on updated forms. The getSaveMode function allow the javascript method executing on the Save event to know why/how the record is being saved. That gives you the flexibility as a developer to add some additional logic to handle your scenario… Below is the list of values returned by the getSaveMode function based on the entity type.

Entity Event Mode Value
All Save 1
All Save and Close 2
All Save and New 59
All AutoSave 70
Activities Save as Completed 58
All Deactivate 5
All Reactivate 6
User or Team owned entities Assign 47
Email (E-mail) Send 7
Lead Qualify 16
Lead Disqualify 15

This is fantastic as you can now write script to handle very specific scenario like an activity being resolved, a record being saved and closed, assigned and other cases. Below is a usage example in which we prevent the auto-save from happening as presented in the SDK documentation:

function preventAutoSave(econtext) {
   var eventArgs = econtext.getEventArgs();
   if (eventArgs.getSaveMode() == 70) {
      eventArgs.preventDefault();
   }
}

Cheers

CRM 2013 – Client API: Save & Refresh

I know these operations seem like very basic functionalities that have been around for a while. I wanted to point a specific new feature that comes with CRM 2013: the ability to run a callback method after a refresh or after a save triggered from a JavaScript method.

In the past, using the old Xrm.Page.data.entity.save method caused a refresh of the page which dismissed any code after the save in your script. Take this scenario for example…

  • You have button in your ribbon on an Account form
  • The button calls an external web service to update some of the account field values based on the account’s Primary Contact value which is on editable on the form
  • The web service only takes the account id as a parameter, it loads the records, reads it and takes action

With the old save method, you had to require that the user saves the account so that the value of Primary Contact is saved to the database, then click your button that will call the web service with account ID. Such a requirement certainly causes pain in user experience especially if there are a lot of situations where they need to hit save, wait for refresh and click another button.

With the new Save and Refresh, we now have the possibility to add callback methods:

Xrm.Page.data.refresh(save).then(successCallback, errorCallback);

// Parameters
// save => A Boolean value to indicate if data should be saved after it is refreshed.
// successCallback => A function to call when the operation succeed
// errorCallbak => A function to call when the operation fails. It gets called with 2 parameters (an error code and a localized error message)

Xrm.Page.data.save().then(successCallback, errorCallback);

// Parameters
// successCallback => A function to call when the operation succeed
// errorCallbak => A function to call when the operation fails. It gets called with 2 parameters (an error code and a localized error message)

Having had this problem in the past makes this one a good candidate for most exciting new client API feature for me 🙂

Cheers

Run multiple requests with one service call using ExecuteMultipleRequest

If you have been developing on for Dynamics CRM for a while, you probably asked yourself this question at least one: why is there not a way to send multiple service requests with a single call to the organization service. It’s finally here. It was introduced with UR12 on CRM 2011 and is of course available for CRM 2013. The request type is ExecuteMultipleRequest. It’s really simple to use. Here are the steps and code snippet below:

  • Create a collection of entity records you need to action on (create or update or delete)
  • Create the ExecuteMultipleRequest object and add the settings:
    • ContinueOnError
    • ReturnResponse
  • Add a request for each entity to the request collection
  • Call the IOrganizationService Execute method and passing the ExecuteMultipleRequest object in parameter
public void ExecutePluginOperation(LocalPluginContext obj)
{
IOrganizationService service = obj.OrganizationService;
IExecutionContext context = obj.PluginExecutionContext;

Incident incident = (context.InputParameters["Target"] as Entity).ToEntity<Incident>();
EntityCollection entitesToCreate = GetEntitiesToCreate(incident);

ExecuteMultipleRequest requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = true,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};

// Add a CreateRequest for each entity to the request collection.
foreach (var entity in entitesToCreate.Entities)
{
if (entity.Id == Guid.Empty)
{
CreateRequest createRequest = new CreateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
}
else
{
UpdateRequest createRequest = new UpdateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
}            }

// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults = (ExecuteMultipleResponse)service.Execute(requestWithResults);
}

Notes:

  • You can only make multiple requests that make changes or create entities of different types (e.g. Contacts, Accounts)
  • You can make multiple requests of different types (create, updates and delete requests in a single call)

It’s a very nice performance optimization in certain scenarios!

CRM 2013 – Client API: Dialogs

CRM 2013 introduces a couple of client side dialog methods under the Xrm.Utility library. The goal is to remove the use of window.open and window.confirm and replaces them with alertDialog and confirmDialog and to support these alert messages in CRM for Tablets. Also, the key difference is that these methods will not block code until a user closes them. However, they contain a callback function parameter to indicate what code should be executed depending on the user’s response.

The Xrm.Utility.alertDialog(message,onCloseCallback) method displays a dialog box that contains a message passed as a parameter. Optionally, you can also execute another method (onCloseCallback) when the OK button is clicked.

var message = "Alert Dialog ! ";
 Xrm.Utility.alertDialog(message, onCloseCallback);
 

The Xrm.Utility.confirmDialog(message, yesCloseCallback, noCloseCallback) method displays a confirmation dialog box that contains an optional message and an OK and a Cancel button. A callback method can be set to run after each of the button is clicked.

var message = "Confirmation Dialog ! ";
 Xrm.Utility.confirmDialog(message, null, null);
 

Again in this case, the methods are only available for “Updated Entities”. You can see my previous post to get the list of entities on which this will not work.

Cheers

CRM 2013 – Client API: Client Methods

The CRM 2013 client API adds a few useful methods. Here I am going to focus on the context.Client methods : context.client.getClient() and context.client.getClientState. These methods are used to find out what kind of client is running and to get the information about it being online or offline. This is useful if you have scripts that you want to run when you are in the web application and nowhere else (not in Outlook client, not on Mobile client). As a consequence of this API change, the previous context.IsOutlookOnline and context.IsOutlookClient are now deprecated.

The getClient method returns the value Web (browser), Outlook (Outlook client) or Mobile (mobile app). The getClientState method returns Online or Offline, the latter applying only to the Outlook and Mobile clients. It’s also worth noting that these methods are only available for what Microsoft calls “Updated Entities”. In short, it’s the entities that have an updated interface (most key entities like Account, Case, Contact, basic activities like Phone Call, Tasks fit into that category). It also works on custom entities.

The entities that are not updated still use the “classic forms” and the Client methods are not supported on these. Here is the list of the entities with classic forms:

Address
Article
Article Comment
Bulk Delete Operation
Connection
Discount
Discount List
Document Location
Email Attachment
Follow
Goal
Goal Metric
Import Source File
Invoice Product
Order Product
Price List
Queue Item
Quote Product
Rollup Field
Rollup Query
Saved View
Service
Service Activity
SharePoint Site
Site
Territory
Unit
Unit Group

Error Logging Options in CRM

Logging is an often frustrating topic when it comes to Dynamics CRM. How do we manage error logging or even debug and verbose/information logging? The answer from Microsoft is simple and standard: use the ITracingService to write logging information. If your requirements are a little more complex, say you need to track your code execution on a very granular level even if no error occurs, then the ITracingService gives you very little options …

  1. In CRM Online, you cannot activate and review the CRM log files (it’s only available with on premise installations)
  2. In CRM Online, you can view the details that are related to the job execution (works for Asynchronous plugins and custom WF); For synchronous plugins, you only see the logs if an error is thrown by downloading the log file – there is no permanent record of the log
  3. If you enable Tracing in CRM (on premise), there is plenty of system written logs in the CRM trace that makes the log file difficult to read and to find your application specific logs, even if you are using the very nice CRM Log Viewer from Stunnware

If you want to have a custom logging module for CRM code, there are a few things to take into consideration:

  • What kind of information do you need to log?
  • Where do you want/need to write it?
  • How and when do you need to access it?
  • Do you need to control the logging level at a given time? (write error messages only, verbose, info etc.)
  • Who will write the logs? Does that user have permission to write in your chosen location?

Here are a couple of options available to create logs from your CRM code. It is up to the development/architecture team to decide what they want to use that fits their need.

Custom External Logging

You can create logging utilities to write logs in locations other than CRM. For example, you could write logs in the Windows Event Viewer, in a text file or even a custom database. There are also third party tools that help you do that as well (NLog, Log4Net…) if you don’t want to start from scratch. The problem here is that if you are writing logs from plugins or workflow activities that are executed as CRM users, chances are these users won’t have permission to write in your designated location. One option is to simply give access to “Everyone” to these locations but this usually goes against most Enterprises’ IT policies. There are probably ways to set up your log writers to impersonate an admin or user with permissions but I have personally never done it.

Pros:

  • Tailored logging engine built for your needs and in a location of your choice

Cons:

  • Doesn’t work for CRM Online (or not easily)
  • Requires system users to have permission to write the logs in the selected location

Custom CRM Entity

Another way to do this is to create one (or many) custom entity to capture your logs. Your CRM custom code can just create new rows in the table(s) to log the required information/error.

Pros:

  • Works for all CRM Installation;
  • Security is simple to manage;
  • Logging information is available directly in CRM;
  • Custom entity can be customized to capture specific logging fields

Cons:

  • Depending on the amount of logging required, your log table(s) may grow really quickly. Think about having a mechanism to clear all unnecessary or outdated logs on a regular basis
  • If you are writing logs in a failing transaction, the entire transaction will be rolled back including creation of logging records. Check out a workaround for this issue here.

These are just a few thoughts on logging and as always in technology, there are probably plenty of other things we can do around logging in CRM. Thought this could be helpful. Feel free to reach out if you want more details or guidance on the topic.