<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[CRM 2015 - Alexander Development]]></title><description><![CDATA[CRM 2015 - Alexander Development]]></description><link>https://alexanderdevelopment.net/</link><image><url>https://alexanderdevelopment.net/favicon.png</url><title>CRM 2015 - Alexander Development</title><link>https://alexanderdevelopment.net/</link></image><generator>Ghost 1.20</generator><lastBuildDate>Thu, 23 Apr 2026 09:36:02 GMT</lastBuildDate><atom:link href="https://alexanderdevelopment.net/tag/crm-2015/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Predictions in Dynamics CRM with custom Azure Machine Learning integrations]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Earlier this year I wrote a <a href="https://alexanderdevelopment.net/post/2015/10/12/sentiment-analysis-in-dynamics-crm-using-azure-text-analytics/">post</a> that showed how to perform sentiment analysis in Dynamics CRM using <a href="https://datamarket.azure.com/dataset/amla/text-analytics">Microsoft Azure Text Analytics</a>. Azure Text Analytics makes it incredibly easy to use sentiment analysis (with English text only), but the full Azure Machine Learning offering is much more powerful. In today's</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/11/30/using-azure-machine-learning-predictive-data-models-in-dynamics-crm/</link><guid isPermaLink="false">5a5837236636a30001b977df</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[Azure]]></category><category><![CDATA[machine learning]]></category><category><![CDATA[data mining]]></category><category><![CDATA[analytics]]></category><category><![CDATA[web services]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Tue, 01 Dec 2015 03:08:34 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/11/ml-03-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/11/ml-03-1.png" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"><p>Earlier this year I wrote a <a href="https://alexanderdevelopment.net/post/2015/10/12/sentiment-analysis-in-dynamics-crm-using-azure-text-analytics/">post</a> that showed how to perform sentiment analysis in Dynamics CRM using <a href="https://datamarket.azure.com/dataset/amla/text-analytics">Microsoft Azure Text Analytics</a>. Azure Text Analytics makes it incredibly easy to use sentiment analysis (with English text only), but the full Azure Machine Learning offering is much more powerful. In today's post I will show how to create a custom predictive web service in Azure ML and make predictions with it in Dynamics CRM.</p>
<h4 id="whyamidoingthis">Why am I doing this?</h4>
<p>One of the exciting announcements about Dynamics CRM 2016 is that it includes some sort of integration with Azure ML, so what's the point of this blog post? Actually, here are two reasons:</p>
<ol>
<li>It's not clear (as of late November 2016) what capabilities the standard CRM-Azure ML integration will have. The approach demonstrated here allows for total customization.</li>
<li>The approach below can be used right now in any version of CRM (online or on-premise) from CRM 2011 onward.</li>
</ol>
<h4 id="thedemodataset">The demo data set</h4>
<p>For this demonstration I am using data from the AdventureWorks data warehouse sample database to build a model to predict whether a contact in CRM is likely to be a bicycle buyer. I created a flat file of contacts that includes several independent variables and a yes/no flag for whether they purchased a bicycle. That sample file is included in my solution source linked at the bottom of this post.</p>
<p>You can also download the full AdventureWorks database from CodePlex <a href="https://msftdbprodsamples.codeplex.com/releases/view/125550">here</a>.</p>
<h4 id="gettingstartedwithazureml">Getting started with Azure ML</h4>
<p>As I was trying to get the hang of Azure ML, I found the <a href="https://bluewatersql.wordpress.com/">Bluewater SQL blog</a> tremendously helpful. If you're just getting started with Azure ML, I suggest you take a look at both of these posts before continuing. <em>(These two posts also use the AdventureWorks data warehouse sample database, though I had already decided to use it for my demo before I found this site. I guess the AdventureWorks data is an obvious choice for this sort of thing.)</em></p>
<ol>
<li><a href="https://bluewatersql.wordpress.com/2014/07/31/azure-machine-learning-first-look/">https://bluewatersql.wordpress.com/2014/07/31/azure-machine-learning-first-look/</a></li>
<li><a href="https://bluewatersql.wordpress.com/2014/08/01/azure-machine-learning-a-deeper-look/">https://bluewatersql.wordpress.com/2014/08/01/azure-machine-learning-a-deeper-look/</a></li>
</ol>
<h4 id="creatingthepredictivewebservice">Creating the predictive web service</h4>
<p>Now that the introductory bits are out of the way, here's an overview of how I set up my predictive web service in Azure ML. I've also shared my work in the Cortana Analytics Gallery, so if you just want to see how the experiments are set up without going through all the steps yourself, skip to the end of this post for the gallery links.</p>
<ol>
<li>Export your data set from CRM. I use a simple KingswaySoft SSIS package to do this. It's included in my sample project files.</li>
<li>Upload your data set to Azure ML Studio. I am using the Azure ML free tier, which requires me to manually upload the data set for the initial upload and any subsequent updates. If I were using the standard tier, it would be possible to upload the data set to Azure blob storage as part of my SSIS package. This would be useful for periodically retraining the model with updated data in the future. <img src="https://alexanderdevelopment.net/content/images/2015/11/ml-01.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></li>
<li>Create and run a new experiment to classify bike buyers. I basically followed the steps outlined in the two Bluewater SQL posts, so take a look at those if you want to see a more detailed explanation. <img src="https://alexanderdevelopment.net/content/images/2015/11/ml-02.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></li>
<li>Save the trained model from this experiment to use in your predictive web service.</li>
<li>Create a new experiment that will serve as the foundation for the predictive web service</li>
<li>Add the following items to the new experiment canvas:</li>
<li>Data set</li>
<li>Trained model from the earlier experiment</li>
<li>Score model component</li>
<li>Project columns transformation between the data set and score model component to exclude the lpa_bikerbuyername column</li>
<li>Project columns transformation after score model component to only include score labels</li>
<li>Run the experiment.</li>
<li>Create a predictive web service. <img src="https://alexanderdevelopment.net/content/images/2015/11/ml-03.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></li>
<li>Run the experiment.</li>
<li>Deploy the web service. <img src="https://alexanderdevelopment.net/content/images/2015/11/ml-04.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></li>
<li>Open the web service and copy the API key to use later. <img src="https://alexanderdevelopment.net/content/images/2015/11/ml-05.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></li>
<li>Open the request/response page.</li>
<li>Copy the post URL to use later. Leave off the &quot;&amp;details=true&quot; at the end. <img src="https://alexanderdevelopment.net/content/images/2015/11/ml-06.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></li>
<li>Scroll down to find the JSON request/response samples and copy them for review later. <img src="https://alexanderdevelopment.net/content/images/2015/11/ml-07.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></li>
</ol>
<h4 id="makingpredictionsfromcrm">Making predictions from CRM</h4>
<p>Once your predictive web service is set up, using it in Dynamics CRM is as simple as posting a JSON request to the web service and then parsing the JSON response. A few years ago, I wrote a <a href="https://code.msdn.microsoft.com/Postingprocessing-JSON-in-396ead03">code sample showing an easy way to make JSON requests from CRM custom assemblies</a> that serves as the foundation for the workflow activity I'm using in this demo. There are only a few changes required to that sample:</p>
<ol>
<li>Add an authorization header that includes the bearer API key you copied earlier.</li>
<li>Add input/output parameters that match the inputs and outputs for your predictive web service. I am also passing the API key and service endpoint as input parameters instead of hardcoding them.</li>
<li>Modify the JSON request/response classes to allow for serialization to/deserialization from the request and response messages. Because of how Azure ML passes the inputs/outputs, these are actually fairly generic, so you can probably use mine with no or minimal changes.</li>
<li>Send the correct request parameters and correctly handle the response parameters.</li>
</ol>
<p>To demonstrate the custom workflow activity, I created a sample CRM dialog.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/ml-08.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></p>
<p>Here's where I supply the input parameters.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/ml-09-1.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></p>
<p>Here's what the dialog looks like when I run it from a contact record.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/ml-10.png#img-thumbnail" alt="Predictions in Dynamics CRM with custom Azure Machine Learning integrations"></p>
<h4 id="thecode">The code</h4>
<p>You can get all the code for this demonstration from my GitHub repository <a href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmAzureMachineLearningDemo">here</a>. The  sample code includes the following:</p>
<ol>
<li>CRM solution containing:</li>
<li>Contact entity with custom fields added and a system view for data export for Azure ML</li>
<li>Sample dialog (you would need to update the parameters with your own API key and endpoint details)</li>
<li>Compiled custom workflow activity to call the web service</li>
<li>Contact data ready for import to CRM</li>
<li>SSIS package solution for data export</li>
<li>Custom workflow activity source code</li>
</ol>
<p>I've also shared my training and prediction experiments in the Cortana Analytics Gallery. Here are the links where you can open and import them into your own workspace:</p>
<ol>
<li><a href="http://gallery.azureml.net/Details/3f87e56096214a508274c4f61e989cfb">Training experiment</a></li>
<li><a href="http://gallery.azureml.net/Details/ec90eadce2c947608916c64fb3c8fb97">Prediction experiment</a></li>
</ol>
<p>What do you think about this approach? Does it seem like it would be useful to you in a real-world situation? Let me know in the comments!</p>
</div>]]></content:encoded></item><item><title><![CDATA[SSIS package for moving access team templates with KingswaySoft]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Last year Ben Hosking said there was <a href="https://crmbusiness.wordpress.com/2014/12/01/crm-2013-why-are-access-teams-marooned/">no way to move access teams between Dynamics CRM organizations</a>, so I created <a href="http://alexanderdevelopment.net/post/2014/12/13/console-application-for-moving-dynamics-crm-access-team-templates/#comment-2308742658">a tool to do that</a>. Last month Tanguy Touzard said I should turn my console application into an <a href="http://disq.us/8qdywm">XrmToolBox plugin</a>, so <a href="http://alexanderdevelopment.net/post/2015/10/20/xrmtoolbox-plugin-for-moving-access-team-templates/">I did</a>. Soon after that <a href="https://twitter.com/danielcai">Daniel Cai</a> said I</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/11/01/ssis-package-for-moving-access-team-templates-with-kingswaysoft/</link><guid isPermaLink="false">5a5837236636a30001b977d7</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[SSIS]]></category><category><![CDATA[KingswaySoft]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 02 Nov 2015 03:13:14 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/11/source-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/11/source-1.png" alt="SSIS package for moving access team templates with KingswaySoft"><p>Last year Ben Hosking said there was <a href="https://crmbusiness.wordpress.com/2014/12/01/crm-2013-why-are-access-teams-marooned/">no way to move access teams between Dynamics CRM organizations</a>, so I created <a href="http://alexanderdevelopment.net/post/2014/12/13/console-application-for-moving-dynamics-crm-access-team-templates/#comment-2308742658">a tool to do that</a>. Last month Tanguy Touzard said I should turn my console application into an <a href="http://disq.us/8qdywm">XrmToolBox plugin</a>, so <a href="http://alexanderdevelopment.net/post/2015/10/20/xrmtoolbox-plugin-for-moving-access-team-templates/">I did</a>. Soon after that <a href="https://twitter.com/danielcai">Daniel Cai</a> said I should make something with the KingswaySoft SSIS Integration Toolkit, so I've now written a version of my access team template mover as an SSIS package.</p>
<h4 id="thelogic">The logic</h4>
<p><a href="http://www.kingswaysoft.com/products/ssis-integration-toolkit-for-microsoft-dynamics-crm">KingswaySoft's Dynamics CRM SSIS adapter</a> makes basic CRM retrieves and inserts easy, so I could have written a simple package to do a full copy of access team templates from a source to a target in about 10 minutes, but I wanted to include the same functionality as my XrmToolBox plugin to enable access teams on the relevant entities in the target organization if desired.</p>
<p>Unfortunately the KingswaySoft adapter doesn't make working with Dynamics CRM metadata easy, so I had to use an SSIS transformation script task to check whether access teams are enabled for a particular entity and enable them.</p>
<p>After the transformation script task checks whether access teams are enabled for the entities in the target organization and (optionally) enables them, a conditional split transformation passes teamtemplate records for entities that are enabled for access teams to a Dynamics CRM destination task to create or update the teamtemplate records in the target organization.</p>
<p>Here's what the data flow task looks like with all the components on the canvas:<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/dataflow.png#img-thumbnail" alt="SSIS package for moving access team templates with KingswaySoft"></p>
<p>Let's take a closer look at all of them.</p>
<h4 id="theretrievetask">The retrieve task</h4>
<p>The data flow starts with a Dynamics CRM source task to retrieve teamtemplate records from the source organization. Although you could use an entity source type, I use FetchXML to offer greater flexibility. For example it would be possible to only sync access teams that have names starting with a particular string value.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/source.png#img-thumbnail" alt="SSIS package for moving access team templates with KingswaySoft"></p>
<h4 id="thetransformationscripttask">The transformation script task</h4>
<p>KingswaySoft's Dynamics CRM adapter supports the use of its connection managers in SSIS script tasks, but there are a few extra steps you need to take that are described in this <a href="http://www.kingswaysoft.com/blog/2013/06/24/Writing-Script-Component-or-Script-Task-using-CRM-Connection-Manager">blog post</a>.</p>
<p>Because SSIS processes the data in a row-by-row fashion, I needed to use slightly different logic in the SSIS package to check for whether entities have access teams enabled and then enable them. In the PreExecute method, the package establishes source/target connections and then retrieves metadata for all the entities in the target system. Next it stores the objecttypecode values for each enabled entity in a list of strings. This actually took me a while to get right, because KingswaySoft returns an entity's logical name as the objecttypecode attribute instead of the actual numeric CRM objecttypecode value.</p>
<p>As the transformation script task loops through each row, it does the following:</p>
<ol>
<li>Check whether the entity is enabled for access teams in the target. If so, set the value of an "enabled" output column to true. 
</li><li>If the entity isn't enabled for access teams in the target organization:<ol>
<li>If a package parameter to automatically enable access teams is set to true, update the entity in the target organization to enable access teams and set the "enabled" output column to true. Also add the entity's logical name to the list of enabled entities so the script won't unnecessarily update the target system if it encounters another teamtemplate record for the same entity later.
</li><li>Otherwise, set the "enabled" output column to false.
</li></ol>
</li></ol>
<h4 id="theconditionalsplit">The conditional split</h4>
<p>The conditional split transformation has two outputs - one for rows with the enabled column set to true and one for rows with the enabled column set to false. My version of the package doesn't actually do anything with the &quot;disabled&quot; output, but you could do something with those rows if you wanted.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/split.png#img-thumbnail" alt="SSIS package for moving access team templates with KingswaySoft"></p>
<h4 id="theupsert">The upsert</h4>
<p>The package creates or updates teamtemplate records in the target organization with a Dynamics CRM destination upsert task.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/upsert-1.png#img-thumbnail" alt="SSIS package for moving access team templates with KingswaySoft"></p>
<p>All the columns are mapped except for the createdby and modifiedby attributes.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/upsert-2.png#img-thumbnail" alt="SSIS package for moving access team templates with KingswaySoft"></p>
<h4 id="packageparameters">Package parameters</h4>
<p>As I mentioned earlier, the package supports optionally enabling entities for access teams in the target system. That's done via a package parameter called &quot;enableTargetAccessTeams.&quot; The package also has additional parameters for setting the source and target connection strings and passwords.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/11/parameters.png#img-thumbnail" alt="SSIS package for moving access team templates with KingswaySoft"></p>
<h4 id="wrappingup">Wrapping up</h4>
<p>You can get the package from my GitHub repository <a href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/SSIS/ReferenceDataMover">here</a>. I hope to add more packages to this solution for synchronizing other reference data records like business units, teams and queues in the near future. Stay tuned!</p>
</div>]]></content:encoded></item><item><title><![CDATA[XrmToolBox plugin for moving access team templates]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Late last year I created a console application for moving access team templates between Dynamics CRM organizations, and I described it in this <a href="https://alexanderdevelopment.net/post/2014/12/12/console-application-for-moving-dynamics-crm-access-team-templates/">blog post</a>. Following up on that, I've created an XrmToolBox plugin to make it even easier to move access team templates (with GUIDs) between CRM organizations. I've</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/10/20/xrmtoolbox-plugin-for-moving-access-team-templates/</link><guid isPermaLink="false">5a5837236636a30001b977d2</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[utilities]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[CRM 2013]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Tue, 20 Oct 2015 22:04:35 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/toolbox-01-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/toolbox-01-1.png" alt="XrmToolBox plugin for moving access team templates"><p>Late last year I created a console application for moving access team templates between Dynamics CRM organizations, and I described it in this <a href="https://alexanderdevelopment.net/post/2014/12/12/console-application-for-moving-dynamics-crm-access-team-templates/">blog post</a>. Following up on that, I've created an XrmToolBox plugin to make it even easier to move access team templates (with GUIDs) between CRM organizations. I've also added functionality to automatically enable access teams on the relevant entities in the target organization if desired.</p>
<p>Let's take a look at the tool in action.</p>
<h4 id="beforeexecution">Before execution</h4>
<p>Here are the access team templates in the source organization.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/source.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>Here are the access team templates in the target organization before we run the tool.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/target-pre.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>Note the &quot;Dog&quot; entity does not have access teams enabled.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/dog-pre.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<h4 id="runningthetool">Running the tool</h4>
<p>First open XrmToolBox. Look at that handsome dog!<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/toolbox-01.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>Next select the Access Team Template Mover plugin and connect to an organization. That organization is set as the source, but you can change it.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/toolbox-02.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>Click the select target button to select the target organization.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/toolbox-03.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>Once both source and target are set, the copy templates button will turn green and become enabled.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/toolbox-04.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>You can also uncheck the option to automatically enable access teams for target organization entities. If you do, you will receive a confirmation prompt.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/toolbox-05.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>Executing the copy with the enable access teams for target organization entities option checked copies three records in this scenario. It updates the access team template that already existed in the target and creates two new ones.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/toolbox-06.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<h4 id="afterexecution">After execution</h4>
<p>Because the enable access teams for target organization entities option was selected, the &quot;Dog&quot; entity in the target now has access teams enabled.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/dog-post.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<p>Finally here is the updated list of access team templates in the target organization.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/target-post-1.png#img-thumbnail" alt="XrmToolBox plugin for moving access team templates"></p>
<h4 id="gettingtheplugin">Getting the plugin</h4>
<p>The source code for the plugin is available in my GitHub repository <a href="https://github.com/lucasalexander/AlexanderDevelopment.AccessTeamTemplateMover">here</a>.</p>
<p>The compiled plugin can be downloaded <a href="https://github.com/lucasalexander/AlexanderDevelopment.AccessTeamTemplateMover/releases/tag/v1.0">here</a>.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Sentiment analysis in Dynamics CRM using Azure Text Analytics]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Last year I created a <a href="https://github.com/lucasalexander/CRM-IdolOnDemand-Tools">proof-of-concept solution</a> that showed how to integrate Dynamics CRM with <a href="https://www.havenondemand.com/">HP Haven OnDemand</a> (then called HP IDOL OnDemand) to perform sentiment analysis and index records to support &quot;find similar&quot; queries. While I was working through the <a href="https://challenge.azurecon.com/">AzureCon challenge</a> a few weeks ago, I</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/10/12/sentiment-analysis-in-dynamics-crm-using-azure-text-analytics/</link><guid isPermaLink="false">5a5837226636a30001b97775</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[text analysis]]></category><category><![CDATA[Azure]]></category><category><![CDATA[analytics]]></category><category><![CDATA[web services]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 12 Oct 2015 22:36:23 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/dialog-2.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/dialog-2.png" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"><p>Last year I created a <a href="https://github.com/lucasalexander/CRM-IdolOnDemand-Tools">proof-of-concept solution</a> that showed how to integrate Dynamics CRM with <a href="https://www.havenondemand.com/">HP Haven OnDemand</a> (then called HP IDOL OnDemand) to perform sentiment analysis and index records to support &quot;find similar&quot; queries. While I was working through the <a href="https://challenge.azurecon.com/">AzureCon challenge</a> a few weeks ago, I thought it would be an interesting exercise to update my sentiment analysis code to work with the <a href="https://datamarket.azure.com/dataset/amla/text-analytics">Text Analytics</a> offering from the Microsoft Azure Marketplace.</p>
<h4 id="theapproach">The approach</h4>
<p>As with my Haven OnDemand solution, the approach I'm using with Azure relies on a custom workflow activity that does the following:</p>
<ol>
<li>Parse a supplied text input and strip any HTML tags using a helper function.
</li><li>Create a JSON sentiment analysis request and post it to Azure Text Analytics with an HttpWebRequest.
</li><li>Deserialize the JSON respsonse returned by Azure Text Analytics to a custom class object using a DataContractJsonSerializer.
</li><li>Return the sentiment score to the calling process.
</li></ol>
<p>There are two main differences with the my Azure Text Analytics solution:</p>
<ol>
<li>The Azure service only returns a sentiment score, so this custom workflow activity doesn't return a positive/negative string value.
</li><li>Instead of embedding an access key in the custom workflow activity code, I've made it a parameter, which means you can take the solution straight from GitHub and start using it in your CRM organization as soon as you sign up for the Text Analytics service.
</li></ol>
<h4 id="thesolutioninaction">The solution in action</h4>
<p>Here's a sample dialog I've created to demonstrate the use of the custom workflow activity.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/dialog.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/dialog-01-input.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/dialog-02-params.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/dialog-03-output.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p>Here's how the process works for the sample text &quot;I hate you.&quot;</p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/hate-01.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/hate-02.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p>Wrapping it up on a more positive note, here's the same dialog with &quot;I love you&quot; instead.</p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/love-01.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/love-02.png#img-thumbnail" alt="Sentiment analysis in Dynamics CRM using Azure Text Analytics"></p>
<p>As you can see, the score for &quot;I hate you&quot; is about .06, and the score for &quot;I love you&quot; is about .91, which makes sense as scores closer to one are more positive, and scores closer to zero are more negative.</p>
<h4 id="thecode">The code</h4>
<p>You can download all the custom code and a CRM solution extract from my <a href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmAzureTextAnalysis">Crm-Sample-Code repository on GitHub</a>. Let me know what you think in the comments!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Get next case functionality for CRM Unified Service Desk]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Last week I shared an approach for implementing <a href="https://alexanderdevelopment.net/post/2015/10/01/get-next-case-functionality-for-dynamics-crm/">next case functionality for Dynamics CRM</a> so that users can get the &quot;next&quot; case to work from a queue just by clicking a button. In today's post I will show an easy way to add the same functionality to Unified</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/10/07/get-next-case-functionality-for-crm-unified-service-desk/</link><guid isPermaLink="false">5a5837226636a30001b97770</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[Unified Service Desk]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Thu, 08 Oct 2015 02:41:36 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/usd-found-case-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/usd-found-case-1.png" alt="Get next case functionality for CRM Unified Service Desk"><p>Last week I shared an approach for implementing <a href="https://alexanderdevelopment.net/post/2015/10/01/get-next-case-functionality-for-dynamics-crm/">next case functionality for Dynamics CRM</a> so that users can get the &quot;next&quot; case to work from a queue just by clicking a button. In today's post I will show an easy way to add the same functionality to Unified Service Desk (USD), but as an added bonus the case will also open in a new session tab.</p>
<p>Before talking through the code and configuration elements in detail, let's take a look at exactly how the get next case button works in my USD demo instance.</p>
<p>I'm displaying the get next button in the left panel, but it can be displayed in any visible panel.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/usd-main.png#img-thumbnail" alt="Get next case functionality for CRM Unified Service Desk"></p>
<p>Once I click the button, a new session is opened if a &quot;next&quot; case is found in the queue.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/usd-found-case.png#img-thumbnail" alt="Get next case functionality for CRM Unified Service Desk"></p>
<p>If no &quot;next&quot; case can be found, an alert message is displayed.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/usd-no-case.png#img-thumbnail" alt="Get next case functionality for CRM Unified Service Desk"></p>
<p>There are three elements to make this work:</p>
<ol>
<li>The custom workflow activity and custom action from my previous blog post.
</li><li>A USD-specific web resource to expose the button and open the "next" case record.
</li><li>USD configuration elements (hosted controls, action calls, etc.) to load the get next case web resource and handle its output.
</li></ol>
<p>Because there are no changes to the existing custom workflow activity or custom action, I'm not going to discuss those further in this post, but let's take a closer look at the other elements.</p>
<h4 id="thewebresource">The web resource</h4>
<p>In my previous post, clicking the &quot;get next case&quot; button searched a queue for a case and then generated a link for a user to manually click to open the case. To streamline the functionality in USD, I decided to modify the web resource to automatically open the case if one is found. If no case can be found in the queue, an alert message is displayed.</p>
<p>Because USD allows you to modify JavaScript logic as described in this <a href="http://blogs.msdn.com/b/usd/archive/2015/09/25/inserting-usd-events-into-html-javascript-logic-and-acting-upon-it.aspx">MSDN post</a>, I considered reusing my existing get next web resource from before, and adjusting the USD configuration to pop open the case record. Ultimately I decided it would be easier to just add a new &quot;USD&quot; version of the web resource, which is included in the CRM solution in the sample code at the bottom of this post. That web resource is almost identical to my previous version except for this section of code:</p>
<pre><code>    //if a case is found
    if(caseId != '00000000-0000-0000-0000-000000000000') {
		var caseUrl = _server + "/main.aspx?etc=112&extraqs=&pagetype=entityrecord&id=%7b" + caseId + "%7d";
		////display the case number as a hyperlink
		//$("#outputdiv").append("Case: <a href="https://alexanderdevelopment.net/post/2015/10/07/get-next-case-functionality-for-crm-unified-service-desk/" + caseUrl + "" target="_blank">" + caseNumber + "</a>");
        //automatically open case record
		window.open(caseUrl);
	}
	else {
		//otherwise display a message that no "next" case could be found
		//$("#outputdiv").append("No next case found");
		alert("No next case found");
	}</code></pre>
<h4 id="theusdconfiguration">The USD configuration</h4>
<p>Once the web resource is ready, the following USD configuration records need to be created:</p>
<ol>
<li>Create a CRM page hosted control to display the get next button web resource. As mentioned above, I am displaying the web resource in the left panel, but it will work in any visible panel.
![Get next case button hosted control](/content/images/2015/10/01-get_next-control.png#img-thumbnail)
</li><li>Create a CRM page hosted control to display the case session.
![Case session hosted control](/content/images/2015/10/02-case_session-control.png#img-thumbnail)
</li><li>Create a session name session information record to display the case number on the session tab. This isn't strictly necessary, but it looks better than "new session."
![Case session name record](/content/images/2015/10/03-session_name.png#img-thumbnail)
</li><li>Create an action call to load the button. As in my previous post, the queue id and assign/remove from queue flags are supplied as encoded query string parameters. I've hardcoded the queue id, but you could use some sort of logic to dynamically set it. Also, you'll note the image here shows the assign and remove from queue flags set to false.
![Load get next action call](/content/images/2015/10/04-get_next-action.png#img-thumbnail)
</li><li>Add the action call to the global manager DesktopReady event.
![Global manager DesktopReady event](/content/images/2015/10/05-desktop_ready.png#img-thumbnail)
</li><li>Create a window navigation rule to display case (incident) records opened from the get next case button hosted control in the case session tab.
![Open case from get next window navigation rule](/content/images/2015/10/06-window_routing.png#img-thumbnail)
</li><li>(Optionally) Update any agent scripting configuration to handle cases being loaded in session tabs. In my USD configuration I already had agent scripting configured for accounts per this <a href="https://msdn.microsoft.com/en-us/library/dn864881.aspx">USD walkthrough</a>, so I created agent scripting for case sessions, too.
![Case agent script](/content/images/2015/10/07-case-script.png#img-thumbnail)
![Load case script action call](/content/images/2015/10/09-case_scripting-action.png#img-thumbnail)
![Case session tab BrowserDocumentComplete event](/content/images/2015/10/08-browser_document_complete.png#img-thumbnail)
</li><li>Finally you need to add all of these elements to the USD configuration record.
</li></ol>
<h4 id="wrappingup">Wrapping up</h4>
<p>You can download a CRM solution with the custom assembly, custom CRM action and web resources from my Crm-Sample-Code repository on <a href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmQueueGetNext/crm">GitHub</a>, but you'll have to do the USD configuration on your own.</p>
<p>What do think about this approach? Could you see yourself using it in your CRM projects? Let me know in the comments!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Get next case functionality for Dynamics CRM]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Dynamics CRM offers sophisticated tools for working with cases and service queues, but sometimes users just want a quick and simple way to get the next case to work. In today's post, I'll share an easy way to implement this functionality in your Dynamics CRM organization.</p>
<p>There are three components</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/10/01/get-next-case-functionality-for-dynamics-crm/</link><guid isPermaLink="false">5a5837226636a30001b9776b</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[C#]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[CRM 2015]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Fri, 02 Oct 2015 02:13:00 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/process-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/process-1.png" alt="Get next case functionality for Dynamics CRM"><p>Dynamics CRM offers sophisticated tools for working with cases and service queues, but sometimes users just want a quick and simple way to get the next case to work. In today's post, I'll share an easy way to implement this functionality in your Dynamics CRM organization.</p>
<p>There are three components to my approach:</p>
<ol>
<li>First, there is a custom workflow activity that searches a queue for unassigned cases and assigns the one that entered the queue earliest to a user. This activity returns the assigned case id and case number as output parameters.
</li><li>Second, there is a CRM action that that acts as a wrapper for the custom workflow activity.
</li><li>Finally, there is a web resource that displays a button to call the CRM action and generate a link to the assigned case (or a message if there are no cases in the queue to assign).
</li></ol>
<p>Let's look at each of these pieces in more detail. If you'd rather get right to the code, scroll to the bottom of this post for a link.</p>
<h4 id="thecustomworkflowactivity">The custom workflow activity</h4>
<p>The custom workflow activity has the following parameters:</p>
<ol>
<li>Queue - input - Reference to the queue that contains the case
</li><li>User - input - Reference to the user who will be assigned the case
</li><li>Assign - input - Flag for whether to assign the case or just return the case details
</li><li>Remove from queue - input - Flag for whether to completely remove the case from the queue when it is assigned
</li><li>Case id - output - Case GUID as a string (string because it makes working with non-existing cases easier in the custom action)
</li><li>Case number - output - Case ticket number value
</li><li>Case found - output - Flag for whether a case was found
</li><li>Case title - output - Case title value
</li></ol>
<p>The activity then executes a FetchXML query to retrieve unassigned cases in ascending order of the date they entered the queue. If the &quot;assign&quot; flag is set to true, the first case is assigned to the user, and then the details are returned as output parameters. If the flag is set to false, the case details are returned as output parameters, but the case is not updated.</p>
<h4 id="thecrmaction">The CRM action</h4>
<p>The action is the simplest part of the solution. It just takes input parameters to pass to the custom activity and then returns the output parameters.</p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/process.png#img-thumbnail" alt="Get next case functionality for Dynamics CRM"></p>
<h4 id="thewebresource">The web resource</h4>
<p>Finally the web resource uses JavaScript to call the action and display a link to the assigned case. If no  &quot;next&quot; case can be found, then a message is displayed to the user. In my solution, the queue id and assign/remove from queue flags are supplied as encoded query string parameters.</p>
<p>The image below shows the output after the get next button is clicked:<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/button.png#img-thumbnail" alt="Get next case functionality for Dynamics CRM"></p>
<p>The web resource approach allows you to embed the button in a dashboard or CRM form through an iframe, but you could also trigger the action from a ribbon button using similar JavaScript.</p>
<h4 id="thecode">The code</h4>
<p>You can download all the custom code and a CRM solution extract from my Crm-Sample-Code repository on <a href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmQueueGetNext">GitHub</a>. Happy case management!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 5]]></title><description><![CDATA[<div class="kg-card-markdown"><p>This the final post in my five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ. In <a href="https://alexanderdevelopment.net/post/2015/01/20/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-3">part 3</a> and <a href="https://alexanderdevelopment.net/post/2015/01/22/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-4">part 4</a> I showed two approaches for building a Dynamics CRM plug-in that publishes notification messages to a RabbitMQ exchange. In today’s post I will show</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/01/27/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-5/</link><guid isPermaLink="false">5a5837236636a30001b977c7</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[C#]]></category><category><![CDATA[JSON]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[RabbitMQ]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Tue, 27 Jan 2015 18:00:00 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-1.png" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 5"><p>This the final post in my five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ. In <a href="https://alexanderdevelopment.net/post/2015/01/20/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-3">part 3</a> and <a href="https://alexanderdevelopment.net/post/2015/01/22/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-4">part 4</a> I showed two approaches for building a Dynamics CRM plug-in that publishes notification messages to a RabbitMQ exchange. In today’s post I will show how to create a Windows console application that reads messages from a queue and writes the data to Dynamics CRM. The code for this application is available on <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub</a> in the LeadWriterSample project under the LucasCrmMessageQueueTools solution.</p>
<h4 id="theapproach">The approach</h4>
<p>This application is extraordinarily simple. On startup it prompts the user to supply connection information for the RabbitMQ queue that it will monitor as well as a Dynamics CRM connection string. It then monitors the queue for new JSON-formatted messages. When new messages arrive, it attempts to deserialize them into a lightweight &quot;leadtype&quot; object, and then it creates new lead records in CRM. Once a message is successfully processed and a lead is created, the application then sends a confirmation back to RabbitMQ so that the message can be removed from the queue.</p>
<p>The following code shows what happens after a connection to the RabbitMQ is established:<pre><code>//wait for some messages<br>
var consumer = new QueueingBasicConsumer(channel);<br>
channel.BasicConsume(_queue, false, consumer);<br>
 <br>
Console.WriteLine(&quot; [*] Waiting for messages. To exit press CTRL+C&quot;);<br>
 <br>
//instantiate crm org service<br>
using (OrganizationService service = new OrganizationService(_targetConn))<br>
{<br>
   while (true)<br>
   {<br>
     //get the message from the queue<br>
     var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();<br>
 <br>
     var body = ea.Body;<br>
     var message = Encoding.UTF8.GetString(body);<br>
 <br>
     try<br>
     {<br>
       //deserialize message json to object<br>
       LeadType lead = JsonConvert.DeserializeObject&lt;LeadType&gt;(message);<br>
 <br>
       try<br>
       {<br>
         //create record in crm<br>
         Entity entity = new Entity(&quot;lead&quot;);<br>
         entity[&quot;firstname&quot;] = lead.FirstName;<br>
         entity[&quot;lastname&quot;] = lead.LastName;<br>
         entity[&quot;subject&quot;] = lead.Topic;<br>
         entity[&quot;companyname&quot;] = lead.Company;<br>
         service.Create(entity);<br>
 <br>
         //write success message to cli<br>
         Console.WriteLine(&quot;Created lead: {0} {1}&quot;, lead.FirstName, lead.LastName);<br>
 <br>
         //IMPORTANT - tell the queue the message was processed successfully so it doesn't get requeued<br>
         channel.BasicAck(ea.DeliveryTag, false);<br>
       }<br>
       catch (FaultException&lt;Microsoft.Xrm.Sdk.OrganizationServiceFault&gt; ex)<br>
       {<br>
         //return error - note no confirmation is sent to the queue, so the message will be requeued<br>
         Console.WriteLine(&quot;Could not create lead: {0} {1}&quot;, lead.FirstName, lead.LastName);<br>
         Console.WriteLine(&quot;Error: {0}&quot;, ex.Message);<br>
       }<br>
     }<br>
     catch(Exception ex)<br>
     {<br>
       //return error - note no confirmation is sent to the queue, so the message will be requeued<br>
       Console.WriteLine(&quot;Could not process message from queue&quot;);<br>
       Console.WriteLine(&quot;Error: {0}&quot;, ex.Message);<br>
     }<br>
   }<br>
}</code></pre></p>
<p>If this were to be used in production, I would have created a Windows service instead of a console application, but I wanted to make it easy to try out different connection parameters.</p>
<h4 id="verifyingtheapplication">Verifying the application</h4>
<p>The queuewriter.js application in the node-app directory in the <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub repository</a> contains a sample web page that can be used to publish lead data to the CRM-Leads queue. If the application is running, you can access the web page at http://&lt;YOUR_SERVER_NAME&gt;:3000/leadform. When the form’s submit button is clicked, an AJAX call posts a JSON object to the Node.js POST endpoint I showed in my previous post. If the LeadWriterSample console application is running, it will take the message from the queue and you will see a new lead record created in CRM. The screenshots below show each piece working.</p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/5-01-lead-form.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 5"><br>
<em>The lead has been submitted via the web form, and a success message has been received from the Node.js endpoint.</em></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/5-02-lead-queue.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 5"><br>
<em>The lead has landed in the CRM-Leads queue and is ready to be retrieved.</em></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/5-03-lead-processed.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 5"><br>
<em>The console application has retrieved and processed the submitted lead message.</em></p>
<p><img src="https://alexanderdevelopment.net/content/images/2015/10/5-04-lead-crm.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 5"><br>
<em>The lead record has been created in CRM.</em></p>
<p>One caveat about the demo lead form is that it has the RabbitMQ credentials embedded in the HTML source, so this code should not be used in production. My approach was originally formulated with the thought that a server-side process would build the JSON message to post to Node.js, so sensitive information would not be exposed. If you decide to use an AJAX post operation like is shown here, you would want to modify the queuewriter.js application to contain the credentials so they do not need to be passed from the end user’s web browser.</p>
<h4 id="wrappingup">Wrapping up</h4>
<p>That does it for this series, but I’ve just barely explored the capabilities of RabbitMQ. There’s so much more you can do with it than what I’ve shown here, and I hope I’ve piqued your interest about how you can use RabbitMQ or any other message broker in your Dynamics CRM projects. If you have any questions or want to continue the discussion, please share your thoughts in the comments.</p>
<p><em>A version of this post was originally published on the HP Enterprise Services Application Services blog.</em></p>
</div>]]></content:encoded></item><item><title><![CDATA[Authenticating from a Node.js client to Dynamics CRM via AD FS and OAuth2]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Last week I decided to finally take a look at using OAuth2 as an authentication protocol with Dynamics CRM. I wanted to understand how it could enable non-Windows clients to consume CRM data. As it turns out, I was unable to find any documentation or comprehensive code samples for non-Windows</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/01/23/authenticating-from-a-node-js-client-to-dynamics-crm-via-ad-fs-and-oauth2/</link><guid isPermaLink="false">5a5837226636a30001b97747</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[JSON]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Sat, 24 Jan 2015 00:00:00 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/adfs-diesel.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/adfs-diesel.jpg" alt="Authenticating from a Node.js client to Dynamics CRM via AD FS and OAuth2"><p>Last week I decided to finally take a look at using OAuth2 as an authentication protocol with Dynamics CRM. I wanted to understand how it could enable non-Windows clients to consume CRM data. As it turns out, I was unable to find any documentation or comprehensive code samples for non-Windows clients, so I put together my own Node.js client, and I've added the code to my Crm-Sample-Code repository on GitHub here: <a href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/NodeClientDemo">https://github.com/lucasalexander/Crm-Sample-Code/tree/master/NodeClientDemo</a>. Having endured a lot of frustration in getting this to work, I'd like to share some additional notes that might be helpful if you decide to start using OAuth2 with CRM.</p>
<p>If you're not already familiar with OAuth2, I suggest you take a look at this post on the Microsoft Dynamics CRM blog that explains how CRM uses OAuth at a high level: <a href="http://blogs.msdn.com/b/crm/archive/2013/12/12/use-oauth-to-authenticate-with-the-crm-service.aspx">http://blogs.msdn.com/b/crm/archive/2013/12/12/use-oauth-to-authenticate-with-the-crm-service.aspx</a>. Although there's no code in that post, it will help you understand how OAuth authentication works.</p>
<h4 id="infrastructureandenvironmentprep">Infrastructure and environment prep</h4>
<p>I am running Dynamics CRM 2015 and Active Directory Federation Services (AD FS) on a single Windows Server 2012 R2 Azure VM. CRM and AD FS are configured for IFD. The CRM website is running on port 443. AD FS is running on port 444.</p>
<p>Before writing any code, I completed all the prep work outlined in this CRM SDK walkthrough - <a href="https://msdn.microsoft.com/en-us/library/dn531010.aspx">https://msdn.microsoft.com/en-us/library/dn531010.aspx</a>. Specifically I enabled OAuth2 for CRM, and I registered an OAuth2 client application in AD FS. Although this was all done as part of an on-premise Dynamics CRM deployment, I don't see any reason that it won't work with CRM Online.</p>
<h4 id="thecode">The code</h4>
<p>Now, let's take a look at the Node.js application. I chose to write a Node.js client instead of something in C# for two main reasons. First, Node.js made it easy for me to inspect and modify all the HTTP headers that are required for getting OAuth2 to work. Second, Node.js is basically server-side JavaScript, so most of the work I've done can be easily ported to a client-side JavaScript implementation.</p>
<p>My Node.js application is written using the <a href="http://expressjs.com/">Express web framework</a>, and it serves four web pages via routes. They are:</p>
<ol start="2">
<li>/ - This is the web application index page. It displays links to the login page and contacts display page.</li>
<li>/auth/login - This page handles redirection of the browser to the AD FS login page.</li>
<li>/auth/callback - This is the page to which AD FS redirects the user's browser after a successful login.</li>
<li>/authenticated/contacts - This page queries the CRM OrganizationData service for contacts using an OAuth token for authentication.</li>
</ol>
<p>The basic flow of the application is:</p>
<ol start="2">
<li>A user starts on the index page. The page checks for an OAuth token in a session variable. If no token is present, a link to the login page is shown. If a token is present, a link to the contact display page is shown.</li>
<li>When a user navigates to the login page, it makes a request to the CRM OrganizationData service to request the correct URL to use for authentication and redirects the browser to that page. The client id, resource name and redirect uri are all included in the query string of the request to AD FS. (See <a href="https://github.com/nordvall/TokenClient/wiki/OAuth-2-Authorization-Code-grant-in-ADFS">https://github.com/nordvall/TokenClient/wiki/OAuth-2-Authorization-Code-grant-in-ADFS</a> for more information on how this works.)</li>
<li>The user authenticates with AD FS, and then AD FS redirects the user to the callback page with an authorization code in the query string.</li>
<li>The callback page parses the authorization code from the query string and sends it to AD FS to request a token. The token is stored in a session cookie, and then the user is redirected to the index page, which should now show a link to the contact display page.</li>
<li>The contact display page reads the token from the session cookie and makes an Odata request to CRM with the token supplied as the authorization header. The results are then parsed and displayed.</li>
</ol>
<p>A few caveats:</p>
<ol start="2">
<li>OAuth2 tokens eventually expire. The default AD FS OAuth2 token expiration value is 3600 seconds (one hour). It is possible to request a new token using a refresh token that is provided at the same time as the authorization token. Using the refresh token allows for reauthorization without needing to supply credentials again. My code sample does not demonstrate use of a refresh token.</li>
<li>My sample application doesn't have much in the way of error handling, and it has not been extensively tested. If you plan to use OAuth with CRM, I highly recommend you don't just deploy my code in production without any further testing.</li>
</ol>
</div>]]></content:encoded></item><item><title><![CDATA[Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 4]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Welcome back to my five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ. In my <a href="https://alexanderdevelopment.net/post/2015/01/20/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-3">last post</a> I showed how to build a Dynamics CRM plug-in that publishes notification messages to a RabbitMQ exchange using the <a target="_blank" href="https://www.rabbitmq.com/dotnet.html" rel="nofollow">official RabbitMQ .Net client library</a>. Unfortunately, that plug-in can’t</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/01/22/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-4/</link><guid isPermaLink="false">5a5837236636a30001b977bf</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[C#]]></category><category><![CDATA[JSON]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[integration]]></category><category><![CDATA[RabbitMQ]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Thu, 22 Jan 2015 18:00:00 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-2.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-2.png" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 4"><p>Welcome back to my five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ. In my <a href="https://alexanderdevelopment.net/post/2015/01/20/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-3">last post</a> I showed how to build a Dynamics CRM plug-in that publishes notification messages to a RabbitMQ exchange using the <a target="_blank" href="https://www.rabbitmq.com/dotnet.html" rel="nofollow">official RabbitMQ .Net client library</a>. Unfortunately, that plug-in can’t successfully communicate with a RabbitMQ server if it’s executed inside the Dynamics CRM sandbox, so in today’s post I will show how to achieve the same results with a sandboxed plug-in. The code for this plug-in is available on <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub</a> in the MessageQueueSandboxPlugin project under the LucasCrmMessageQueueTools solution.</p>
<h4 id="theapproach">The approach</h4>
<p>As I mentioned in my previous post, last month I wrote a series of blog posts about how to create a near real-time streaming API using plug-ins and Node.js. That plug-in worked fine in the Dynamics CRM sandbox, and Node.js can easily publish messages to a RabbitMQ exchange, so today’s plug-in will post a JSON-formatted message to a Node.js application, and then that Node.js application will do the actual publishing to RabbitMQ. As a result, I only need to make a couple of minor modifications to <a href="https://alexanderdevelopment.net/post/2014/12/09/creating-a-near-real-time-streaming-interface-for-dynamics-crm-with-node-js-part-3/">my earlier Node.js message-posting plug-in</a> so that it can pass the RabbitMQ connection parameters to my Node.js application. Additionally, the Node.js application that I described in my earlier series only needs a few changes to publish the message to a RabbitMQ exchange instead of sending it to Socket.IO clients.</p>
<h4 id="theplugin">The plug-in</h4>
<p>The plug-in is registered for an operation (create, update, delete, etc.) with a FetchXML query in its unsecure configuration. When the plug-in step is triggered, its associated FetchXML query is executed, and then the resulting fields are serialized into a JSON object, which is then sent to a Node.js application called queuewriter.js via an HTTP POST request. The JSON object also needs to contain RabbitMQ connection details, so I pass them as part of the plug-in step’s unsecure configuration. Here’s the configuration XML fragment to enable case notifications:</p>
<pre><code>&lt;nodeendpoint&gt;http://lucas-ajax.cloudapp.net:3000/rabbit_post_endpoint&lt;/nodeendpoint&gt;
&lt;endpoint&gt;lucas-ajax.cloudapp.net&lt;/endpoint&gt;
&lt;exchange&gt;CRM&lt;/exchange&gt;
&lt;routingkey&gt;Case&lt;/routingkey&gt;
&lt;user&gt;rabbituser&lt;/user&gt;
&lt;password&gt;PASSWORDHERE&lt;/password&gt;
&lt;query&gt;&lt;![CDATA[
&lt;fetch mapping='logical'&gt;
&lt;entity name='incident'&gt;
&nbsp;&lt;attribute name='ownerid'/&gt;
&nbsp;&lt;attribute name='modifiedby'/&gt;
&nbsp;&lt;attribute name='createdby'/&gt;
&nbsp;&lt;attribute name='title'/&gt;
&nbsp;&lt;attribute name='incidentid'/&gt;
&nbsp;&lt;attribute name='ticketnumber'/&gt;
&nbsp;&lt;attribute name='createdon'/&gt;
&nbsp;&lt;attribute name='modifiedon'/&gt;
&nbsp;&lt;filter type='and'&gt;
&nbsp; &lt;condition attribute='incidentid' operator='eq' value='{0}' /&gt;
&nbsp;&lt;/filter&gt;
&lt;/entity&gt;
&lt;/fetch&gt;
]]&gt;
&lt;/query&gt;
&lt;/config&gt;</code></pre>
<p>Just like in my <a href="https://alexanderdevelopment.net/post/2014/12/09/creating-a-near-real-time-streaming-interface-for-dynamics-crm-with-node-js-part-3/">earlier Node.js plug-in</a>, the FetchXML is extracted from the configuration XML, and the query is executed against Dynamics CRM. The results are then serialized to JSON using <a target="_blank" href="http://james.newtonking.com/json" rel="nofollow">Json.NET</a> just like before, except the serialized CRM data is included as a &quot;message&quot; object that is part of a parent JSON object that includes the RabbitMQ connection parameters. Here’s an example of the structure:<pre><code>{<br>
   &quot;endpoint&quot;:&quot;lucas-ajax.cloudapp.net&quot;,<br>
   &quot;username&quot;:&quot;rabbituser&quot;,<br>
   &quot;password&quot;:&quot;XXXXXXXX&quot;,<br>
   &quot;exchange&quot;:&quot;CRM&quot;,<br>
   &quot;routingkey&quot;:&quot;Lead&quot;,<br>
   &quot;message&quot;:{<br>
     &quot;property1&quot;:&quot;value 1&quot;,<br>
     &quot;property2&quot;:&quot;value 2&quot;,<br>
     &quot;property3&quot;:&quot;value 3&quot;<br>
   }<br>
}</code></pre></p>
<p>Because this plug-in uses the Json.NET client library, it has to be merged with the plug-in assembly before registering it in Dynamics CRM. I’ve included a batch script called ilmerge.bat in the project directory on <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub</a>.</p>
<h4 id="thenodejsapplication">The Node.js application</h4>
<p>The Node.js application (queuewriter.js) waits to receive JSON messages via HTTP POST from a client. When it receives a POST request, it checks whether the message is valid JSON. If it is, the RabbitMQ connection parameters are extracted and then the notification &quot;message&quot; object is published to the RabbitMQ exchange. If everything is successful, it sends &quot;success&quot; back as a response to the client. If any errors are encountered, it sends back a descriptive error message. I am using the <a target="_blank" href="https://github.com/postwait/node-amqp" rel="nofollow">node-amqp</a> library for communicating with the RabbitMQ server, but the behavior isn’t that different from a .Net client. Here’s an extract with the relevant code:<pre><code>if (request.method == 'POST') {<br>
   request.on('data', function(chunk) {<br>
     //check if received data is valid json<br>
     if(IsJsonString(chunk.toString())){<br>
       //convert message to json object<br>
       var requestobject = JSON.parse(chunk.toString());<br>
      <br>
       //connect to rabbitmq<br>
       var connection = amqp.createConnection({ host: requestobject.endpoint<br>
       , port: 5672 //assumes default port<br>
       , login: requestobject.username<br>
       , password: requestobject.password<br>
       , connectionTimeout: 0<br>
       , authMechanism: 'AMQPLAIN'<br>
       , vhost: '/' //assumes default vhost<br>
       });<br>
      <br>
       //when connection is ready<br>
       connection.on('ready', function () {<br>
          //get the &quot;message&quot; property of the supplied request<br>
          var message = JSON.stringify(requestobject.message);<br>
         <br>
          //post it to the exchange with the supplied routing key<br>
          connection.exchange = connection.exchange(requestobject.exchange, {passive: true, confirm: true }, function(exchange) {<br>
            exchange.publish(requestobject.routingkey, message, {mandatory: true, deliveryMode: 2}, function () {<br>
              //if successful, write message to console<br>
              console.log('Message published: ' + message);<br>
             <br>
              //send &quot;success&quot; back in response<br>
              response.write('success');<br>
             <br>
              //close the rabbitmq connection and end the response<br>
              connection.end();<br>
              response.end();<br>
            });<br>
          });<br>
       });<br>
      <br>
       //if an error occurs with rabbitmq<br>
       connection.on('error', function () {<br>
          //send error message back in response and end it<br>
          response.write('failure writing message to exchange');<br>
          response.end();<br>
       });<br>
     }<br>
     else {<br>
       //if request contains invalid json<br>
       //send error message back in response and end it<br>
       response.write(&quot;invalid JSON&quot;);<br>
       response.end();<br>
     }<br>
   });<br>
}</code></pre></p>
<p>The complete queuewriter.js application is contained in the node-app directory in the <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub repository</a>.</p>
<h4 id="wrappingup">Wrapping up</h4>
<p>In addition to registering the plugin and registering a step to publish a notification message to RabbitMQ, you need to deploy and start the queuewriter.js application to publish messages. Once that’s done, you can verify everything is working as expected either by looking at the Queues tab in the RabbitMQ management web UI or running the CliConsumer sample application I showed in <a href="https://alexanderdevelopment.net/post/2015/01/14/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-2">part 2</a>.</p>
<p>Obviously using queuewriter.js as message proxy adds an extra layer of complexity, and you have to make sure that the application is up and running in order to process message, but it also offers a couple of advantages. First, by using queuewriter.js instead of a direct connection, you can easily use this same plug-in with different message brokers like Apache ActiveMQ and Microsoft’s Azure Service Bus. Second, the queuewriter.js application isn’t limited to just handling messages outbound from Dynamics CRM. You can also use it to process inbound messages without any changes. You just have to configure a client application to read messages from the queue and process them accordingly. A good example of this would be writing data submitted through a web form to Dynamics CRM via a RabbitMQ queue, and I will show that exact scenario in my next post!</p>
<p><em>A version of this post was originally published on the HP Enterprise Services Application Services blog.</em></p>
</div>]]></content:encoded></item><item><title><![CDATA[Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 3]]></title><description><![CDATA[<div class="kg-card-markdown"><p>This is the third post of a five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ.<br>
<a href="https://alexanderdevelopment.net/post/2015/01/14/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-2">Last time</a> I showed how to install and configure a RabbitMQ server to support passing messages to and from Dynamics CRM. Today I will show how to build a Dynamics</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/01/20/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-3/</link><guid isPermaLink="false">5a5837236636a30001b977b7</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[JSON]]></category><category><![CDATA[C#]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[RabbitMQ]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Tue, 20 Jan 2015 18:00:00 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-3.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-3.png" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 3"><p>This is the third post of a five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ.<br>
<a href="https://alexanderdevelopment.net/post/2015/01/14/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-2">Last time</a> I showed how to install and configure a RabbitMQ server to support passing messages to and from Dynamics CRM. Today I will show how to build a Dynamics CRM plug-in that publishes notification messages to a RabbitMQ exchange using the <a target="_blank" href="https://www.rabbitmq.com/dotnet.html" rel="nofollow">official RabbitMQ .Net client library</a>. The code for this plug-in is available on <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub</a> in the MessageQueuePlugin project under the LucasCrmMessageQueueTools solution.</p>
<p>Before going any further, let’s get some bad news out of the way. Plug-ins that execute in the Dynamics CRM sandbox cannot use RabbitMQ .Net client library to publish messages to a RabbitMQ server, so you can’t use today’s plug-in approach from a CRM Online organization. In my next post, I will be showing an alternate mechanism for publishing messages that you can use from a sandboxed plug-in, but today I want to focus on the most direct integration method. Now that we’re clear on the limitations of this approach, let’s get started!</p>
<h4 id="theapproach">The approach</h4>
<p>Last month I wrote a series of blog posts about how to create a near real-time streaming API using plug-ins and Node.js. For this plug-in I’m going to basically copy the logic I used for the plug-in in that series.</p>
<p><a href="https://alexanderdevelopment.net/post/2014/12/09/creating-a-near-real-time-streaming-interface-for-dynamics-crm-with-node-js-part-3/">This post</a> outlines the approach in detail, but if you don’t want to read the entire thing, the basic idea was to create a plug-in that is registered for an operation (create, update, delete, etc.) with a FetchXML query in its unsecure configuration. When the plug-in step is triggered, its associated FetchXML query is executed, and then the resulting fields are serialized into a JSON object, which is then sent to the Node.js application via an HTTP POST request. Today’s plug-in operates in the exact same way, except instead of sending the JSON object to a Node.js endpoint, the JSON object will be published as a message to a RabbitMQ exchange.</p>
<h4 id="configuringtheplugin">Configuring the plug-in</h4>
<p>To make the plug-in easily useable in any organization without needing to be recompiled, all the RabbitMQ connection parameters are stored in the unsecure configuration along with the FetchXML query for the data to retrieve. Here’s the configuration XML fragment to enable case notifications:</p>
<pre><code>&lt;config&gt;
&lt;endpoint&gt;lucas-ajax.cloudapp.net&lt;/endpoint&gt;
&lt;exchange&gt;CRM&lt;/exchange&gt;
&lt;routingkey&gt;Case&lt;/routingkey&gt;
&lt;user&gt;rabbituser&lt;/user&gt;
&lt;password&gt;PASSWORDHERE&lt;/password&gt;
&lt;query&gt;&lt;![CDATA[
&lt;fetch mapping='logical'&gt;
&lt;entity name='incident'&gt;
&nbsp;&lt;attribute name='ownerid'/&gt;
&nbsp;&lt;attribute name='modifiedby'/&gt;
&nbsp;&lt;attribute name='createdby'/&gt;
&nbsp;&lt;attribute name='title'/&gt;
&nbsp;&lt;attribute name='incidentid'/&gt;
&nbsp;&lt;attribute name='ticketnumber'/&gt;
&nbsp;&lt;attribute name='createdon'/&gt;
&nbsp;&lt;attribute name='modifiedon'/&gt;
&nbsp;&lt;filter type='and'&gt;
&nbsp; &lt;condition attribute='incidentid' operator='eq' value='{0}' /&gt;
&nbsp;&lt;/filter&gt;
&lt;/entity&gt;
&lt;/fetch&gt;
]]&gt;
&lt;/query&gt;
&lt;/config&gt;</code></pre>
<h4 id="generatingthenotificationmessage">Generating the notification message</h4>
<p>Just like in my Node.js plug-in, the FetchXML is extracted from the configuration XML, and the query is executed against Dynamics CRM. The results are then serialized to JSON using <a target="_blank" href="http://james.newtonking.com/json" rel="nofollow">Json.NET</a>.</p>
<h4 id="publishingthemessage">Publishing the message</h4>
<p>The endpoint, exchange name, RabbitMQ user, RabbitMQ password and routing key values from the configuration XML are then used to establish a connection to RabbitMQ and publish the notification message to the exchange like so:</p>
<pre><code>try
{
&nbsp;&nbsp;&nbsp;&nbsp; //connect to rabbitmq
&nbsp;&nbsp;&nbsp;&nbsp; var factory = new ConnectionFactory();
&nbsp;&nbsp;&nbsp;&nbsp; factory.UserName = \_brokerUser;
&nbsp;&nbsp;&nbsp;&nbsp; factory.Password = \_brokerPassword;
&nbsp;&nbsp;&nbsp;&nbsp; factory.VirtualHost = "/";
&nbsp;&nbsp;&nbsp;&nbsp; factory.Protocol = Protocols.DefaultProtocol;
&nbsp;&nbsp;&nbsp;&nbsp; factory.HostName = \_brokerEndpoint;
&nbsp;&nbsp;&nbsp;&nbsp; factory.Port = AmqpTcpEndpoint.UseDefaultPort;
&nbsp;&nbsp;&nbsp;&nbsp; IConnection conn = factory.CreateConnection();
&nbsp;&nbsp;&nbsp;&nbsp; using (var connection = factory.CreateConnection())
&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; using (var channel = connection.CreateModel())
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //tell rabbitmq to send confirmation when messages are successfully published
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; channel.ConfirmSelect();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; channel.WaitForConfirmsOrDie();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //prepare message to write to queue
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var body = Encoding.UTF8.GetBytes(jsonMsg);
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var properties = channel.CreateBasicProperties();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; properties.SetPersistent(true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //publish the message to the exchange with the supplied routing key
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; channel.BasicPublish(_exchange, _routingKey, properties, body);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp; }
}
catch (Exception e)
{
&nbsp;&nbsp;&nbsp;&nbsp; tracingService.Trace("Exception: {0}", e.ToString());
&nbsp;&nbsp;&nbsp;&nbsp; throw;
}</code></pre>
<p>If any errors are encountered, the message is captured via the tracing service, and then an exception is thrown.</p>
<p>Because this plug-in uses both the RabbitMQ .Net and Json.NET client libraries, they have to be merged with the plug-in assembly before registering it in Dynamics CRM. I’ve included a batch script called ilmerge.bat in the project directory on <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub</a>.</p>
<h4 id="wrappingup">Wrapping up</h4>
<p>After you register the plugin and register a step to publish a notification message to RabbitMQ, you can verify everything is working as expected either by looking at the Queues tab in the RabbitMQ management web UI or running the CliConsumer sample application I showed in<br>
<a href="https://alexanderdevelopment.net/post/2015/01/14/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-2">part 2</a>.</p>
<p><em>A version of this post was originally published on the HP Enterprise Services Application Services blog.</em></p>
</div>]]></content:encoded></item><item><title><![CDATA[Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Welcome back to this five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ. In my <a href="https://alexanderdevelopment.net/post/2015/01/12/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-1">last post</a> I discussed why you would want to incorporate a message broker into your Dynamics CRM data interfaces, and today I will show how to install and configure RabbitMQ to</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/01/14/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-2/</link><guid isPermaLink="false">5a5837236636a30001b977af</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[RabbitMQ]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[C#]]></category><category><![CDATA[integration]]></category><category><![CDATA[JSON]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Wed, 14 Jan 2015 18:00:00 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-4.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-4.png" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"><p>Welcome back to this five-part series on creating loosely coupled data interfaces for Dynamics CRM using RabbitMQ. In my <a href="https://alexanderdevelopment.net/post/2015/01/12/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-1">last post</a> I discussed why you would want to incorporate a message broker into your Dynamics CRM data interfaces, and today I will show how to install and configure RabbitMQ to support the examples I’ll be presenting in the rest of the series.</p>
<h4 id="installation">Installation</h4>
<p>First, you’ll need to download the installation files from here: <a target="_blank" href="http://www.rabbitmq.com/download.html" rel="nofollow">http://www.rabbitmq.com/download.html</a>. The RabbitMQ server runs on Windows, Linux, UNIX and Mac OS X, and there are installation guides for each supported platform. Because RabbitMQ is written in Erlang, you will need to install an Erlang VM before you can install RabbitMQ, but there is a download link provided in the installation guide. I set up my RabbitMQ server on a Windows 2012 server, and I was up and running in less than 10 minutes.</p>
<p>Once you’ve installed RabbitMQ and started the server, the easiest way to manage it is via the <a target="_blank" href="http://www.rabbitmq.com/management.html" rel="nofollow">web-based management interface</a> that’s included with the server distribution. You can enable the management interface with the <a target="_blank" href="https://www.rabbitmq.com/man/rabbitmq-plugins.1.man.html" rel="nofollow">rabbitmq-plugins tool</a>. Run the following command to enable it: <em>rabbitmq-plugins enable rabbitmq_management</em>.</p>
<p>After the management plugin is enabled, you can access the web management UI from your server at <a href="http://localhost:15672">http://localhost:15672</a>. The default username is &quot;guest&quot; with &quot;guest&quot; as the password.</p>
<p>You’ll also need to configure any firewall rules necessary to allow access to your RabbitMQ server if it’s running on a server separate from your Dynamics CRM server. The default port is 5672, but that can be changed if you like. <a target="_blank" href="https://www.rabbitmq.com/configure.html" rel="nofollow">This page</a> discusses RabbitMQ configuration in great detail.</p>
<h4 id="settingupusersqueuesandexchanges">Setting up users, queues and exchanges</h4>
<p>The first thing you should do after the install is complete is change your default guest user password via the management UI. Then you can add additional users as necessary. For the examples in the rest of this series, you’ll need a user with full permissions on the default &quot;/&quot; virtual host. Here is what my &quot;rabbituser&quot; user account looks like:<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-00-user.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<p>Next you need to create the entities required to broker the messages between publishers and consumers. Before continuing, I recommend you take a moment to skim this <a target="_blank" href="https://www.rabbitmq.com/tutorials/amqp-concepts.html" rel="nofollow">Advanced Message Queuing Protocol (AMQP) overview document</a>. If nothing else, at least read through the &quot;hello, world&quot; example section because it’s a great introduction to concepts that will be important throughout the rest of this series.</p>
<p><u>Queues</u><br>
In the management UI, navigate to the Queues tab, and create two new durable queues named CRM-Cases and CRM-Leads. (You can create any queues you want, but my examples in the rest of this series use queues with those names.) The screenshot below shows the queues in my system.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-01-queues.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<p><u>Exchanges</u><br>
After your queues are created, you can create an exchange and bindings to your queues so messages get routed correctly. Navigate to the Exchanges tab and create a new, durable exchange named CRM. After your CRM exchange is created, you should see something like the screenshot below.</p>
<p>Next, click on the name of the CRM exchange to open its edit screen. Scroll to the &quot;add binding&quot; section toward the bottom of the page and add a binding to the CRM-Cases queue for a routing key value of &quot;Case&quot; live in the following picture and click &quot;bind.&quot;<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-02-exchanges-1.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<p>Do the same for the CRM-Leads queue with &quot;Lead&quot; as the routing key. You should then see the two queues bound to the exchange.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-02-exchanges-2.PNG" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<h4 id="checkingtheconfiguration">Checking the configuration</h4>
<p>At this point you should have everything in place to start publishing and consuming messages. You can verify your configuration works with the CliProvider and CliConsumer sample applications included in my <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmMessageQueuing" rel="nofollow">GitHub repository</a> as part of the LucasCrmMessageQueueTools solution.</p>
<p>First, build and run the CliProvider application. You will be prompted to supply basic connection details, and then you can type a message to publish to your RabbitMQ server.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-03a-cliprovider.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<p>Once the message has been published, you can verify there’s a message waiting in the correct queue on the Queues tab of the management UI.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-03b-message-ready.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<p>Next, build and run the CliConsumer application. Once it connects to the CRM-Cases queue, the message will be retrieved and displayed.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-03c-cliconsumer.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<p>When the CliConsumer application processes a message, it sends a confirmation back to queue that triggers removal of the message from the queue. You can check the Queues tab in the management UI to verify that the CRM-Cases queue is empty.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/2-03d-no-message-ready.PNG#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 2"></p>
<h4 id="wrappingup">Wrapping up</h4>
<p>That’s it for today. Your RabbitMQ server is now fully configured and ready for use with the examples in the rest of this series. Next time I will show how to send messages to a RabbitMQ exchange from a plug-in using the RabbitMQ .Net client library. See you then!</p>
<p><em>A version of this post was originally published on the HP Enterprise Services Application Services blog.</em></p>
</div>]]></content:encoded></item><item><title><![CDATA[Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 1]]></title><description><![CDATA[<div class="kg-card-markdown"><p>One of the things I love about Dynamics CRM is how easy it is to create data interfaces to enable integration with other systems. If you’ve worked with Dynamics CRM for any length of time, you’ve probably seen multiple web service integrations that enable interoperability with other line-of-business</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/01/12/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-1/</link><guid isPermaLink="false">5a5837236636a30001b977a7</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2015]]></category><category><![CDATA[C#]]></category><category><![CDATA[JSON]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[RabbitMQ]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 12 Jan 2015 18:00:00 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-5.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker-5.png" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 1"><p>One of the things I love about Dynamics CRM is how easy it is to create data interfaces to enable integration with other systems. If you’ve worked with Dynamics CRM for any length of time, you’ve probably seen multiple web service integrations that enable interoperability with other line-of-business and legacy systems. A typical pair of inbound and outbound integrations might look like the picture below.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound.png#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 1"></p>
<p>Using a tightly coupled connection between the source and target systems is usually the easiest (thus the quickest and cheapest) way to establish an integration, but this is often a bad idea. Consider the inbound scenario in which an external application is sending data to Dynamics CRM. What happens if the calling application misbehaves and starts sending thousands of requests per second? This has the potential to overload your CRM server and make it completely unusable. Now consider the outbound scenario in which a CRM plug-in calls an external web service. If the destination application’s web service is offline for a few minutes, the update from the CRM plug-in will not get received unless there’s some sort of error handling and retry logic built into the plug-in</p>
<h4 id="analternateapproach">An alternate approach</h4>
<p>For these reasons, and lots of others (logging, security, scalability, just to name a few), it’s considered a best practice to create loosely coupled integrations that rely on a message broker that sits between the source and destination systems. Though the formal definition is more complicated, for our purposes a message broker can be thought of as a collection of queues that hold messages. Publishers write messages to queues, and then consumers pick up the messages and process them appropriately. Additionally, the message broker can be configured to keep messages in their queues until the consumers provide confirmation of successful processing.</p>
<p>Here’s an example of what the integrations I showed earlier would look like with a message broker.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/inbound-outbound-broker.png#img-thumbnail" alt="Using RabbitMQ as a message broker in Dynamics CRM data interfaces – part 1"></p>
<p>For the outbound call from the CRM plug-in, the plug-in writes the message to a broker. The message is routed to a queue where it waits to be processed. A separate processing service application retrieves the message from the queue and sends it to the destination application. For the inbound call to CRM, the process works exactly the same, except the source and destination applications are reversed.</p>
<h4 id="whyisamessagebrokerbetter">Why is a message broker better?</h4>
<p>In the inbound call scenario, an effective message broker would typically be expected to handle a larger volume of inbound messages than Dynamics CRM because all it’s doing is receiving and routing the data without any additional processing. The processing service can then process the messages in the queue at a speed that doesn’t overload the Dynamics CRM server. In the case of the outbound call, the combination of a message broker and processing service can enable complex retry logic and custom logging without having to store it in the plugin layer. As an added bonus to either scenario, a message broker can provide a guarantee that messages don’t get lost between the source and destination systems as long as the message is successfully published to the broker.</p>
<h4 id="wheredowegofromhere">Where do we go from here?</h4>
<p>Over the course of my next four blog posts, I will show how to use <a target="_blank" href="https://www.rabbitmq.com/" rel="nofollow">RabbitMQ</a> as a message broker in your Dynamics CRM data interfaces. I chose RabbitMQ for this series for several reasons:</p><ol><li>It’s open source.</li><li>It runs on multiple platforms.</li><li>It’s easy to install and configure.</li><li>It’s fast at processing messages.</li></ol><p></p>
<p>If you already have a different message broker in place in your organization or you would like to try a different message broker like Apache ActiveMQ or Microsoft’s Azure Service Bus, most of the approaches and a lot of the code I’m going to show in this series will still be applicable, with the notable exception of the post that discusses how to install and configure RabbitMQ.</p>
<p>Here’s the roadmap for the rest of the series:</p><ul><li>Part 2 – basic installation and configuration of a RabbitMQ</li><li>Part 3 – creating a Dynamics CRM plug-in that publishes messages using the RabbitMQ .Net client library</li><li>Part 4 – creating a sandboxed Dynamics CRM plug-in that publishes messages to RabbitMQ via Node.js</li><li>Part 5 – reading messages from a queue and writing them to Dynamics CRM</li></ul><p></p>
<p>If you just can’t wait to dig into the code, I’ve already posted everything to my <a target="_blank" href="https://github.com/lucasalexander/Crm-Sample-Code#crmmessagequeuing" rel="nofollow">repository on GitHub</a>, so you can go ahead and take a look.</p>
<p>See you next time!</p>
<p><em>A version of this post was originally published on the HP Enterprise Services Application Services blog.</em></p>
</div>]]></content:encoded></item></channel></rss>