Capitalizing on Microsoft Dynamics CRM 3.0 Callouts: Advanced Features

Capitalizing on Microsoft Dynamics CRM 3.0 Callouts: Advanced Features

he first article in this series looked at the basics of using callouts, their integral components, and how to create a simple callout. The rest of this series discusses more advanced callout techniques of exception handling, debugging, logging, evaluating workflows, improving performance, and making callouts asynchronous.

Handling Callout Exceptions
You can define and manage how your code handles callout exceptions:

  • In the Callout.config.xml file
  • During pre-callout enumeration
  • In try/catch/finally blocks

Each item in the preceding list is discussed briefly in the following sections.

Handling Exceptions in Callout.config.xml
The code below shows a typical Callout.config.xml file:

                  @all       @all              

The subscription element in the preceding configuration file contains an attribute called onerror, which by default is set to “abort,” which causes CRM to abort the method if an unhandled exception occurs in the callout code. When that happens, CRM also displays a dialog box on the client side. Alternatively, you can set the value of onerror to “ignore,” which causes CRM to ignore any unhandled exception and continue with the method.

Handling Exceptions during Pre-Callout Enumeration
The Microsoft.Crm.Platform.Callout.Base class contains an enumeration called PreCalloutReturnValue. This enumeration has three return values that can help in handling the exceptions:

  • Continue: This is the default return value. When CRM returns this value the pre-callout has completed successfully and CRM can continue executing any other callouts specified for the same entity.
  • Abort: If this value is returned, additional callouts are not processed. If you return abort, you should also specify an error message in the errorMessage parameter which should be displayed in the dialog box on the CRM user interface.
  • Stop: If this value is returned, it means that the callout has completed successfully but additional callouts will not be processed.

Handling Exceptions in try/catch/finally Blocks
Of course, you always have the option of using try/catch/finally to handle exceptions. It’s good practice to log the messages in the catch block because that aids in debugging.

Debugging, Logging and Tracing in Callouts
The best way to show how to test and debug callouts is to create a sample Windows application and step through the code. The downloadable sample code contains a project you can use; however, if you build one yourself, be sure to add references to the CRM web service and to Microsoft.Crm.Platform.Callout.Base. Then you can add the callout class to the project and call its method to debug the code.

Platform-Level Tracing
If you want to debug the callout beyond the callout code at the platform level, consider turning tracing on using the registry. There are keys available for this purpose at the following locations:

  • HKEY_LOCAL_MACHINESoftwareMicrosoftMSCRM (applies to CRM web server)
  • HKEY_CURRENT_USERSoftwareMicrosoftMSCRMClient (applies to CRM Outlook client)

You may set those registry keys to any of the possible values shown in Table 1.

Table 1. Registry Callout-Tracing Key Values: You can set the two CRM registry key values to these values.
Name Type Data
TraceDirectorystringAn existing directory
See also  Strengthening Business Cybersecurity With Threat Intelligence

Author’s Note: Applying incorrect registry values can bring the entire CRM server down or even cause Windows to crash. Enabling tracing also affects performance. Use tracing only while debugging, and turn it off after you’re done.

Configure the CRM UI to Display Detailed Error Messages
In case there is a platform-level issue with your callout code and you want detailed error messages rather than the friendly but not always informative message displayed by CRM, consider changing the web.config file on your CRM server. You can do this by following these steps:

  1. On the CRM server, navigate to the web root directory (the default is C:inetpubwwwroot).
  2. Locate and open the web.config file.
  3. Change the value of the DevErrors key to On.
  4. Save the file.
  5. Use the Event log to view errors.

You can also use log error messages from your callout code to the Event log. Logging the messages typically provides sufficient information to debug the code effectively. Be sure to wrap your message-logging code in a try/catch/finally block when you log messages to the event log as shown in Listing 1.

In Listing 1, the post-callout method is PostUpdate(), and the method body is wrapped in a try/catch/finally block. Because callouts do not call Dispose methods, you must clean up all resources in the finally block to avoid memory leaks. The WriteTolog method called in the catch block writes the messages to the Event log. The code logs only inside the catch block using the error type EventLogEntryType.Error.

It is also a good idea to log any informational messages (values of important variables, etc.) in the Event log after each important step in the code. Doing so will help you nail down the problem precisely when debugging an issue.

Logging to Event log can degrade the performance, so you might consider creating an app.config file and adding a key called debug to it. You can set debug to true when you are debugging on your local server and then set it to false when you deploy to your production server.

Understanding Workflows and Callouts
Like callouts, MSCRM workflows also provide you with the ability to plug in a custom assembly using the configuration file. When to use callouts and when to use workflows requires a careful decision. Here are few points that can help you decide between workflows and callouts

  • If you need synchronous processing consider using callouts instead of workflows.
  • If you need asynchronous processing, use workflows.
  • Workflow assemblies work only with entities that they own, so if you want to access customer entities (which are owned by the organization), use callouts.
  • Many actions—such as sending email—are already defined in the Workflow Manager. If your need fits well into one of those scenarios, you won’t have to write any code, and you should prefer workflows in such cases.
  • Callouts cannot be executed manually. If you want your users to execute some rules manually, use workflows.
  • If you need to modify data before it gets inserted or updated, prefer callouts.
See also  Integrating Artificial Intelligence into Software Development Practices

For example, suppose you wanted to implement a rule in the CRM server that whenever an account entity gets updated, the system should send an email to the sales team. That kind of scenario is best implemented using a post callout, because it requires immediate action, and the transaction should be synchronous.

Limitations of Callouts
Callouts have several limitations, including:

  • No support for asynchronous processing
  • “Heavier” callouts adversely affect performance
  • No supports for failover

Building Light Callouts
If you must use a callout you can work around the limitations by following these general guidelines. Try to minimize the code as much as possible. In most cases, you can read the incoming XML message (preImageEntityXml or postImageEntityXml) and store it in some data store, such as a database, a text file, MSMQ, etc., referred to hereafter as a “message store.” That way, you can create a Windows service to poll the message store periodically, read any new messages, and perform any required processing on them.

For example, you could write the Windows service to read the polling interval from a configuration file. The Windows service will then process records at a predefined interval, essentially making the callout processing asynchronous. Following this approach, all the callout does is store the incoming message; the Windows service handles all other processing, which makes the callout “light.”

In addition, because the messages are saved in a message store, if an error occurs while processing a message, you can recover it later.

Alternatively, you could use a Windows Communication Foundation (WCF) service in place of the Windows service. Another approach is to replace the message store/Windows service combination with SQL Server 2005 broker services, if those meet your needs.

Example MSMQ/Windows Service Callout
Here’s a callout example that uses the design techniques discussed in the preceding section. This example uses MSMQ for the message store. The example is a post callout that fires after a sales lead gets updated in MSCRM.

Here’s the callout constructor:

   public LeadCallout()   {      try      {         eventLog = new EventLog();         eventLog.Log = "Application";         eventLog.Source = "LeadIntegrationCallout";                        XmlDocument doc = new XmlDocument();         string assemblyName = System.Reflection.Assembly.            GetExecutingAssembly().Location.ToString();         string assemblyFolder = assemblyName.Substring(0,             assemblyName.LastIndexOf(@""));         string configFilePath = assemblyFolder + @"" +             "Lead Callout.config";                        doc.Load(configFilePath);                        XmlNode node = doc.SelectSingleNode("//appSettings");         if (node == null)            throw new InvalidOperationException(               "appSettings section not found in config file.");         queuePath = ((XmlElement)node.SelectSingleNode(            string.Format("//add[@key='{0}']","QueuePath"))).            GetAttribute("value").ToString();         debug = ((XmlElement)node.SelectSingleNode(            string.Format("//add[@key='{0}']","Debug"))).            GetAttribute("value").ToString();         useBinaryFormat = ((XmlElement)node.SelectSingleNode(            string.Format("//add[@key='{0}']",            "UseBinaryFormatter"))).            GetAttribute("value").ToString();         WriteToLog("Constructor Called",             EventLogEntryType.Information);         WriteToLog("Config File Path: " + configFilePath,             EventLogEntryType.Information);         WriteToLog("Assembly Folder: -----> " +             assemblyFolder, EventLogEntryType.Information);      }      catch (Exception ex)      {         WriteToLog(ex.ToString(), EventLogEntryType.Error);      }   }   

The constructor code reads the following values from the configuration file of the callout DLL (the Lead callout.config):

  • QueuePath: Specifies the path of the MSMQ queue to use for storing messages.
  • UseBinaryFormatter: Determines whether to store messages in binary format in the MSMQ
  • CreateQueue: Indicates whether the queue exists or whether to create the queue via code.
  • Debug: Controls whether to log the messages in the Event log.
  • LogFilePath: Specifies the path of the log file.
See also  Essential Real Estate Tech Trends: Innovations Every Agent Must Understand

Please note that the Lead callout.config is different from the callout configuration file; when you create a callout, a callout configuration file gets added as part of the solution, named callout.config.xml.

A Post-Callout Example
Listing 2 shows an example that illustrates how to design and implement post callouts.

As Listing 2 shows, the post callout logs some messages, checks the lead status, and when it’s and MSCRMLEAD, calls the ProcessLeads() method to insert the record in the queue. To keeping this article focused on the callout itself, we won’t discuss the implementation methods here, but you can download the code for all the methods (MSMQ handling, obtaining the status code, logging, etc.).

Deploying the Callout
To deploy the sample callout, you can place the LeadIntegrationCRMCallout.dll, the Lead callout.config, and the callout.config.xml files in the same location: C:Program FilesMicrosoft CRMserverinassembly, (assuming you installed MSCRM on the C: drive).

With a callout that writes incoming messages to the MSMQ queue complete, you now need to create the Windows service that reads the queue and processes the messages. Just like the callout, the Windows service has a config file that will look much like this one:


In that configuration file, the attributes used are:

  • QueuePath: Specifies the path of the MSMQ queue.
  • Polling Interval: Controls the number of seconds to wait between checking the queue for new messages.
  • ReceiveTimeout: Controls the number of seconds to wait before stopping the receive operation from MSMQ.
  • DeleteMessageOnRecieve: If this value is false, the service will leave all messages stored in the queue for later reference; otherwise, it deletes them from the queue after processing.
  • Debug: If true, logs the messages to the Event log.

You can find the code for the Windows service used here in the downloadable code for this article, but briefly, the service uses a timer ticked every N seconds where N is the PollingInterval value specified in the configuration. The service reads messages from the Queue and does some custom processing. If the processing was successful, it deletes the record from the queue (if the DeleteMessageOnRecieve attribute value in the configuration file is true).

MSCRM 3.0 callouts are a powerful feature. When used with proper design techniques, callouts make the CRM engine far more extensible, and can provide seamless integration with other systems.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist