Recently, I was asked by Microsoft to give a presentation on how to integrate CRM online with on premises applications, on the Techdays in Belgium. While hybrid integration was totally not new for me, the challenge here was to learn the extensibility capabilities and integration aspects of CRM online. And I have to say, I was happily surprised with the extensibility framework that Dynamics CRM Online provides, especially with the Plugin mechanism.
All code of this article will be added with the second blog post of this series.
Extending CRM Online
There are different ways to extend CRM Online. This is possible through forms customization, or by injecting Ajax/Silverlight controls. However, these customizations are only applied on changes and events that happen through the front end. Knowing that more and more actions of a CRM applications (especially data creation) are getting automated, I believe that customization should be injected in the actual ‘processing pipeline’ of CRM. And that is where custom plugins come into the picture.
Getting started
Getting started is very straightforward.
- If you don’t have a CRM online account, it is very easy to create a trial account (which is only valid for 30 days). Just browse to http://www.crmonline.com and register for a trial account, using your Windows Live Id (WLID).
- After this, you need to get the CRM SDK. This one can be downloaded here.
- Once you have the SDK downloaded, you should build the PluginRegistration project, that can be found in %sdk%\tools\pluginregistration directory. You will use this tool to inject plugins and create endpoints on your CRM system.
Writing custom plugins
Every plugin you create, needs to implement the IPlugin interface, which has one method; Execute. These plugins should then be linked with the corresponding CRM event, through the PluginRegistrationTool.
using Microsoft.Xrm.Sdk;
namespace CRMPlugins
{
public class MyPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{ }
}
}
Implementing a ‘Base plugin’
Soon, I noticed that almost every plugin has some generic code that is applicable to almost all plugins. For that, I created an abstract class BasePlugin, that every plugin will implement. This BasePlugin takes care of a lot of common aspects:
- Tracking: plugins can now easily track events and logging info, in case exceptions occur.
- Configuration: plugins can receive external configuration, when linked with an event (example: connection strings, passwords, service bus settings…) This configuration is then passed as a string to the plugin constructor, where one can parse it.
- Entity filtering: some plugins should only be executed against specific entities (for example: only for invoices, only for salesorders…). It is possible in the BasePlugin to filter out the entity, just by passing in the entity logical name with the constructor.
- OrganizationService: the organization service allows to query and lookup entities that are configured on the CRM system. This service is made available to every executing plugin.
- Entity handling: reading and updating attributes on entities is made generic now.
- Exception handling: all exceptions are caught and handled in a consistent way.
Implementing a plugin now just comes down to writing the specific logic and not bothering about the general logic that is always the same. The only things left are the following:
public override void InternalExecute(IServiceProvider serviceProvider, Microsoft.Xrm.Sdk.Entity entity)
{}
All the following plugins are using this Base Plugin class, in order to focus on the actual logic and abstract away all CRM specific logic. (for that, you can easily find resources and blogs online).
Writing a plugin: sending a text message to the invoicee
As a first test, I created a plugin that sends a Text message, when an invoice gets created. For this, it looks up the phone number of the account, linked with that invoice. To send the plugin, we just use an existing online service (www.smsbox.be), that exposes the texting functionality through an HTTP endpoint.
Execution logic
The execution logic for the plugin is pasted below. The following steps take place
- First, the invoice number and amount are read from the Entity. (the entity is of type “invoice”, because we have passed the “invoice” as an argument to the BasePlugin constructor). To read these values, we call the base method ReadAttribute.
- If the customerId attribute is available, we make an EntityReference, using the customerId value and we retrieve that account through the OrganizationService (provided by the BasePlugin). We also specify (for performance reasons) that we only want to receive the telephone number attribute.
- If that attribute is available, we send the Text message to the right phone number. Full code is available in the provided zip file.
// Obtain the target entity from the input parmameters.
string invoiceNr = ReadAttribute(entity, "invoicenumber", "(unknown)");
string amount = ReadAttribute(entity, "totalamount", "0");
if (entity.Attributes.Contains("customerid"))
{
EntityReference Customer = (EntityReference)entity["customerid"];
if (Customer.LogicalName == "account")
{
Entity Account = OrganizationService.Retrieve("account", Customer.Id, new ColumnSet(new string[] { "address1_telephone1" }));
string phoneNr = ReadAttribute(Account, "address1_telephone1", null);
if (phoneNr != null)
{
SendSms(phoneNr, string.Format("Invoice {0} has been created for you with the amount of {1}", invoiceNr, amount), null);
}
}
}
Sending the SMS
For those who are interested, the code to do the HTTP post to the smsbox.be endpoint is pasted below:
private void SendSms(string phoneNumber, string text, ITracingService tracingService)
{
try
{
phoneNumber = phoneNumber.Replace("+", "");
string prefix = phoneNumber.Substring(0, 2);
string phoneNr = phoneNumber.Substring(2);
WebRequest request = WebRequest.Create(string.Format("http://www.smsbox.be/scripts/sendsms.php?login=####&pwd=####&prefix={0}&number={1}&message={2}", prefix, phoneNr, text));
request.Method = "POST";
var response = request.GetResponse();
response.Close();
}
catch (Exception ex)
{
if (tracingService != null)
tracingService.Trace(ex.Message);
throw;
}
}
Registering the plugin with the PluginRegistration tool.
As indicated earlier, you need the PluginRegistrationTool to register the plugin on the CRM system and to link it with the corresponding events. To do that, follow these steps:
- Open the PluginRegistrationTool
- Enter the discovery URL of your CRM account. This can be found in the CRM portal, in the resources section.
- Enter the WLID that is linked with your CRM online subscription and click connect, to enter the password.
- In the left pane, you now can see all CRM subscriptions that belong to your WLID. Double clicking one of them will retrieve the entire customization profile.
- Now you can add assemblies, plugins and endpoints and save them to your CRM instance.
- Now it’s time to upload our assembly with the plugin. For that, it’s as easy as clicking the Register new assembly button in the toolbar and selecting the plugin.
- For CRM Online, the only Isolation Mode that is available, is the Sandbox mode, meaning you have reduced functionality.
- The assembly should be deployed to the database, since the Disk or GAC is not available in CRM Online.
- Once everything is configured, clicking the Register Selected Plugins will upload and register the plugin on the CRM Online system.
- The plugin we have created, should be executed, when a new invoice is created. To do that, we need to register a new step for the plugin.
- Select the plugin and click Register new step. This pops up a new window, where we need to provide the following information.
- Message: this is the type of event. In this case, we type Create (notice the intellisense, while typing)
- Primary Entity: the logical name of the entity to which the event will be linked. In this case, we select invoice. (case sensitive)
- Then we can specify the execution order and security context in which the plugin should be executed.
- The plugin can be executed at a specific time in the processing pipeline. Pre-validation, Pre-operation and Post-operation. In this case, we will execute the action, when the invoice has been saved in the system. Therefore, we select the post-operation stage.
- The execution mode defines if the user will be waiting during the exeuction of the pipeline (synchronous mode). Asynchronous mode will increase the user experience, but when this action fails, it is not visible to the end user and only visible to the administrators through the CRM portal.
- On the right, it is possible to specify configuration values that will be passed to the constructor of the plugin. (we handle this in the BasePlugin)
- That’s all that is needed to link our custom action with the right event on CRM Online. Straight forward and easy, isn’t it?
CRM out of the box service bus connectivity
Dynamics CRM provides some out of the box capabilities to integrate events with the Azure Service Bus on different levels: Messaging and Relay. For that you first need to configure the Access Control Service (ACS). This is typically a complex step, but the registration tool makes this extremely easy and shows a perfect example of how Microsoft is using its own components and capabilities in a good way.
To do this, you need to register a new service bus endpoint through the PluginRegistrationTool. (Register New Service Endpoint).
- Here we need to provide the following settings:
- Now we need to specify our service bus namespace and the path to our queue/topic or service endpoint.
- It’s also needed to specify the type of endpoint in the Contract drop down: Oneway, Queue, TwoWay, Rest.
- Secondly, we need to configure the ACS settings for this endpoint, so that the CRM online system has access to the service bus endpoint.
- Clicking on Save & Configure ACS opens a new tool window, where we need to specify the management key and the issuer name for that key.
- We also need to upload a certificate. This public certificate key can be downloaded from the CRM online portal by clicking on Settings > Customizations > Developer Resources and Download Certificate.
- After clicking the Configure ACS button, we get a nice log, indicating what this wizard has done for us. The highlights are pasted below:
Trying to find out the ACS Version.
ACS Version is: V2
Creating ManagementService for codittest-sb
Created RelyingParty with Name: testqueue, RealmName: http://codittest.servicebus.windows.net/testqueue, ID: 10004406
Created RuleGroup with Name: Rule group for testqueue
Assigned RuleGroup to RelyingParty
Created Rule: sampleorgsendrule
Created Rule: sampleownersendrule
Created Rule: sampleownerlistenrule
Created Rule: sampleownermanagerule
- To test if the ACS was configured successfully, it is possible to click on the Save & Verify Authentication button.
Messaging capabilities
It is possible to use the Plugin Registration tool to register a service bus messaging endpoint. This endpoint can then be of type queue, but it also works with topics (since both topics and queues are exposing the same REST interface). On this endpoint, it is also possible to register a step, linked with an event. When this event is fired, the entity will be serialized and written to the messaging endpoint. From then on, it is possible to use the receiver functionality to receive these entities from the messaging endpoint.
There is one downside, however. No properties are being added to the BrokeredMessage, which makes it hard to use the publish/subscribe pattern through subscriptions that are using a routing filter.
Relay service capabilities
The Relay service capabilities can also be leveraged through these endpoints, but then it is required that the on premises service, exposed over the service bus relaying endpoint implements the specific contract (Microsoft.Xrm.Sdk.IServiceEndpointPlugin), as indicated in the SDK documentation. A sample service can be found in the SDK (%SDK%\samplecode\cs\azure\onewaylistener). This application exposes itself on the service bus endpoint through WsHttpRelayBinding.
Conclusion
Microsoft Dynamics CRM Online is truly a good and well-designed product that leverages the various capabilities and components that the Microsoft platform is offering. It provides a very extensible plugin model and application concepts in order to configure and customize the application. Next to that, it also provides some out of the box capabilities to integrate with the various Azure Service Bus capabilities, including relaying and messaging.
However, these out of the box integration capabilities have some limitations and my next post will show how to work around these limitations.
Sam Vanhoutte, Codit
042942b3-8081-4084-919b-24283bbfd012|4|5.0