<?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[web services - Alexander Development]]></title><description><![CDATA[web services - Alexander Development]]></description><link>https://alexanderdevelopment.net/</link><image><url>https://alexanderdevelopment.net/favicon.png</url><title>web services - Alexander Development</title><link>https://alexanderdevelopment.net/</link></image><generator>Ghost 1.20</generator><lastBuildDate>Fri, 24 Apr 2026 14:20:34 GMT</lastBuildDate><atom:link href="https://alexanderdevelopment.net/tag/web-services/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Azure Text Analytics sentiment analysis with North52]]></title><description><![CDATA[<div class="kg-card-markdown"><p>For the last several months I've been working on an enterprise Dynamics CRM project where one of our goals is to minimize the amount of custom code we write by using <a href="http://www.north52.com/business-process-activities/">North52's Business Process Activities</a>. I had not been exposed to North52 before working on this project, but I have</p></div>]]></description><link>https://alexanderdevelopment.net/post/2016/05/17/azure-text-analytics-sentiment-analysis-with-north52/</link><guid isPermaLink="false">5a5837236636a30001b9782d</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[text analysis]]></category><category><![CDATA[integration]]></category><category><![CDATA[Azure]]></category><category><![CDATA[analytics]]></category><category><![CDATA[web services]]></category><category><![CDATA[North52]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Tue, 17 May 2016 13:19:37 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2016/05/2016-05-17_08-51-04.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2016/05/2016-05-17_08-51-04.png" alt="Azure Text Analytics sentiment analysis with North52"><p>For the last several months I've been working on an enterprise Dynamics CRM project where one of our goals is to minimize the amount of custom code we write by using <a href="http://www.north52.com/business-process-activities/">North52's Business Process Activities</a>. I had not been exposed to North52 before working on this project, but I have been pleasantly surprised with how much it has allowed our mostly functional resources to achieve without needing technical assistance.</p>
<p>While looking through North52's documentation a while back, I noticed it could be used to <a href="http://support.north52.com/knowledgebase/articles/488697-introduction-to-north52-s-webfusion">call a REST web service</a>. This got me thinking about how I could rework my <a href="https://alexanderdevelopment.net/post/2015/10/12/sentiment-analysis-in-dynamics-crm-using-azure-text-analytics/">Sentiment analysis in Dynamics CRM using Azure Text Analytics</a> sample using North52 instead of a custom workflow activity.</p>
<p>I found I was able to replace the custom workflow activity with a North52 <a href="http://www.north52.com/business-process-activities/process-genie-for-microsoft-dynamics-crm-xrm/">Process Genie</a>. It executes a <a href="https://datamarket.azure.com/dataset/amla/text-analytics">Smart Flow</a> to call the Azure Machine Learning <a href="https://datamarket.azure.com/dataset/amla/text-analytics">Text Analytics API</a> and then return the result to the calling CRM dialog.</p>
<p>Here's the formula I used in my Process Genie:</p>
<pre><code>SmartFlow(
  SetVar('jsoninput', CreateJObject( 
     CreateJProperty('Inputs', 
           CreateJArray(CreateJObject(
                           CreateJProperty('Id', '1'),  
                           CreateJProperty('Text', [account.texttoanalyze]) 
                              )
                        )
                     )
               )
          ),

  CallRestAPI(
      SetRequestBaseURL('https://api.datamarket.azure.com/data.ashx/amla/text-analytics/v1'),
      SetRequestResource('/GetSentimentBatch'),
      SetRequestDetails('POST'),
      SetRequestHeaders(),
      SetRequestParams('RawContentTextJSON',GetVar('jsoninput')),
      SetRequestAuthenticationBasic('AccountKey','YOUR_AZURE_ML_API_KEY_HERE'),
      SetRequestFiles(),
      SetRequestExpected('OK'),
      SetRequestActionPass(SetVar('result', GetVarJsonValue('SentimentBatch{0}.Score'))),
      SetRequestActionFail(SetVar('result', 'ERROR' + GetVarJsonValue('Errors{0}.Message')))
    ), 

   SmartFlowReturn(GetVar('result'))
)
</code></pre>
<p>Here's a screenshot of my CRM dialog:<br>
<img src="https://alexanderdevelopment.net/content/images/2016/05/2016-05-16_19-30-01.png#img-thumbnail" alt="Azure Text Analytics sentiment analysis with North52"></p>
<p>To execute the Process Genie, you use a North52 N52 Process Genie step like this:<br>
<img src="https://alexanderdevelopment.net/content/images/2016/05/2016-05-16_19-32-09.png#img-thumbnail" alt="Azure Text Analytics sentiment analysis with North52"></p>
<p>The Formula ShortCode value is the short code of the North52 Process Genie. The Formula Parameter Xml value contains the text to analyze from the dialog input in the format expected by the formula:</p>
<p><code>&lt;account&gt;&lt;texttoanalyze&gt;{Response Text(Get text)}&lt;/texttoanalyze&gt;&lt;/account&gt;</code></p>
<p>If were going to use this in real solution, I would not hardcore the Azure ML API key directly in the formula. Other than that I think this is a production-ready approach.</p>
<p>What do you think? Would you consider using something like this as an alternative to writing your own custom code?</p>
</div>]]></content:encoded></item><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[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[Custom identity class to represent Dynamics CRM users in WCF services]]></title><description><![CDATA[<div class="kg-card-markdown"><p>A few weeks ago I wrote a post called <a href="https://alexanderdevelopment.net/post/2013/08/01/custom-wcf-service-authentication-using-microsoft-dynamics-crm-credentials-2/">&quot;Custom WCF service authentication using Microsoft Dynamics CRM credentials&quot;</a> in which I showed how to secure Windows Communication Foundation (WCF) web services using Dynamics CRM usernames and passwords. In that post, I used a GenericIdentity object to store the</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/08/26/custom-identity-class-to-represent-dynamics-crm-users-in-wcf-services/</link><guid isPermaLink="false">5a5837236636a30001b9777c</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[web services]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 26 Aug 2013 13:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>A few weeks ago I wrote a post called <a href="https://alexanderdevelopment.net/post/2013/08/01/custom-wcf-service-authentication-using-microsoft-dynamics-crm-credentials-2/">&quot;Custom WCF service authentication using Microsoft Dynamics CRM credentials&quot;</a> in which I showed how to secure Windows Communication Foundation (WCF) web services using Dynamics CRM usernames and passwords. In that post, I used a GenericIdentity object to store the CRM user information, but unfortunately the GenericIdentity class is extremely limited in the amount of user-related information it can hold, so in this post I will show how to create and use a custom identity object to represent CRM users. In addition to making it simple to store and use attributes like phone number, name and address, this will also allow you to easily enumerate a CRM user's roles or team assignments where necessary, which cannot be done directly with a GenericIdentity object.</p>
<p>Here's a visual depiction of how my custom WCF service authentication helps facilitate easier integration between external systems and a Dynamics CRM solution.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/wcf-blog-post.png#thumbnail-png" alt=""></p>
<p>There are three things I want to cover in this post:<ol><li>The custom identity class</li><li>Retrieving and storing user data in a custom identity object</li><li>Accessing the stored user data</li></ol></p>
<p><strong>The custom identity class</strong></p>
<p>The CrmIdentity class implements the System.Security.Principal.IIdentity interface. My class includes the following public properties and methods:<pre><code>public string Name<br>
public string Email<br>
public string FirstName<br>
public string LastName<br>
public Guid UserId<br>
public string[] Teams<br>
public string[] Roles<br>
public bool IsAuthenticated<br>
public string AuthenticationType<br>
public void SetAuthenticated(bool authFlag)<br>
public void AddRole(string roleName)<br>
public void RemoveRole(string roleName)<br>
public bool InRole(string roleName)<br>
public void AddTeam(string teamName)<br>
public void RemoveTeam(string teamName)<br>
public bool InTeam(string teamName)</code></pre></p>
<p>You can download the complete CrmIdentity class<br>
<a href="https://github.com/lucasalexander/Crm-Sample-Code/blob/master/misc-code-samples/crmidentity.cs">here</a>.</p>
<p><strong>Retrieving and storing the user data</strong></p>
<p>I've updated the Validate method from my original post to store the retrieved user attributes and roles in a CrmIdentity object. (Retrieving and storing teams is left as an exercise for the reader.) The CrmIdentity object is then used to create a GenericPrincipal object that will be used in the actual service class. Here is the updated Validate method:</p>
<pre><code>public override void Validate(string username, string password)
{
	//get the httpcontext so we can store the user guid for impersonation later
	HttpContext context = HttpContext.Current;
	//if username or password are null, obvs we can't continue
	if (null == username || null == password)
	{
		throw new ArgumentNullException();
	}
	//get the crm connection
	Microsoft.Xrm.Client.CrmConnection connection = CrmUtils.GetCrmConnection(username, password);
	//try the whoami request
	//if it fails (user can't be authenticated, is disabled, etc.), the client will get a soap fault message
	using (OrganizationService service = new OrganizationService(connection))
	{
		try
		{
			WhoAmIRequest req = new WhoAmIRequest();
			WhoAmIResponse resp = (WhoAmIResponse)service.Execute(req);
			Entity systemuser = CrmUtils.GetSystemUser(resp.UserId, service);
			CrmIdentity crmIdentity = new CrmIdentity();
			crmIdentity.Name = (string)systemuser["fullname"];
			crmIdentity.FirstName = (string)systemuser["firstname"];
			crmIdentity.LastName = (string)systemuser["lastname"];
			crmIdentity.Email = (string)systemuser["emailaddress1"];
			crmIdentity.UserId = resp.UserId;
			crmIdentity.SetAuthenticated(true);
			List<string> roles = CrmUtils.GetUserRoles(resp.UserId, service);
			foreach (string role in roles)
			{
				crmIdentity.AddRole(role);
			}
			context.User = new GenericPrincipal(crmIdentity, roles.ToArray());
		}
		catch (System.ServiceModel.Security.MessageSecurityExcep<wbr>tion ex)
		{
			throw new FaultException(ex.Message); 
		}
		catch (Exception ex)
		{
			throw new FaultException(ex.Message);
		}
	}
}</string></code></pre>
<p><strong>Accessing the stored user data</strong></p>
<p>Finally, when you want to access the stored user data inside your service, you access the current request's HttpContext object and cast its User.Identity object as a CrmIdentity object like so:</p>
<pre><code>HttpContext context = HttpContext.Current;
CrmIdentity crmIdentity = (CrmIdentity)context.User.Identity;</code></pre>
<p>How do you handle authentication and authorization for your custom Dynamics CRM solution web services? Would you find it easier to use a completely separate authorization mechanism? Let us know 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[Diesel Xrm Service Wrapper Now on GitHub]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Last week I wrote a post called &quot;<a href="https://alexanderdevelopment.net/post/2013/07/31/introducing-the-diesel-xrm-service-wrapper">Introducing the Diesel Xrm Service Wrapper</a>,&quot; in which I presented a generic WCF wrapper for the Dynamics CRM Organization Service. Almost immediately I had several ideas about updates I wanted to make, so I've decided to host the project on GitHub.</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/08/04/diesel-xrm-service-wrapper-now-on-github/</link><guid isPermaLink="false">5a5837226636a30001b976d2</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[C#]]></category><category><![CDATA[web services]]></category><category><![CDATA[FetchXML]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 05 Aug 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Last week I wrote a post called &quot;<a href="https://alexanderdevelopment.net/post/2013/07/31/introducing-the-diesel-xrm-service-wrapper">Introducing the Diesel Xrm Service Wrapper</a>,&quot; in which I presented a generic WCF wrapper for the Dynamics CRM Organization Service. Almost immediately I had several ideas about updates I wanted to make, so I've decided to host the project on GitHub. The project GitHub page is <a href="http://lucasalexander.github.io/DieselXrmWrapper/">here</a>, and you can find the code repository <a href="https://github.com/lucasalexander/DieselXrmWrapper">here</a>.</p>
<p>Here's a current list of enhancements I plan to add over the coming months:</p>
<ol start="2">
<li>Storing query FetchXml and related configuration data as custom entities in Dynamics CRM</li>
<li>Role-based authorization for individual queries</li>
<li>Varying impersonation settings per individual query</li>
<li>Updates</li>
<li>REST/JSON interfaces</li>
</ol>
<p>If you'd like to contribute or have any other interesting ideas, please drop me a line via my <a href="https://alexanderdevelopment.net/forms/contact-us">contact page</a>.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Custom WCF service authentication using Microsoft Dynamics CRM credentials]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Enterprise Microsoft Dynamics CRM implementations frequently require developing custom Windows Communication Foundation (WCF) web services to be used for integration with external systems. Typical use cases for custom web services would include situations in which a consuming system can't easily access the Dynamics CRM Organization Service, or a custom service</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/08/01/custom-wcf-service-authentication-using-microsoft-dynamics-crm-credentials-2/</link><guid isPermaLink="false">5a5837236636a30001b97780</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[web services]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Thu, 01 Aug 2013 22:03:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Enterprise Microsoft Dynamics CRM implementations frequently require developing custom Windows Communication Foundation (WCF) web services to be used for integration with external systems. Typical use cases for custom web services would include situations in which a consuming system can't easily access the Dynamics CRM Organization Service, or a custom service is required to do some data processing above and beyond the capabilities of the CRM Organization Service. Because these custom web services are separate from the actual Dynamics CRM system, user authentication and authorization has to be handled via a separate mechanism.</p>
<p>In this post I will show how you can use a custom WCF username and password validator to authenticate consumers using their Dynamics CRM credentials. In addition to providing an easy-to-use authentication mechanism, this approach will give you the ability to authorize consumers’ access to web services based on their assigned Dynamics CRM roles.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/10/wcf-blog-post.png#img-thumbnail" alt="WCF Custom Dynamics CRM Username and Password Validator"></p>
<p>There are three steps required to set up custom username and password validation for a WCF service:</p>
<ol><li>Create the custom validator class</li><li>Update the service binding's security configuration</li><li>Update the service behavior to use the custom validator</li></ol>
<p>Let's look at all three in more detail.</p>
<p><strong>The custom validator</strong></p>
<p>The custom validator is a class that inherits from the System.IdentityModel.Selectors.UserNamePasswordValidator class. That class contains a Validate method that we will need to override. The Validate method accepts two parameters, username and password, and if the validation fails, it throws a SecurityTokenException. If validation is successful, the method exits without returning anything.</p>
<p>In our custom validator class, we need to do the following:</p>
<ol><li>Create a connection to the Dynamics CRM Organization Service via the CRM SDK</li><li>Execute a WhoAmIRequest using the provided user credentials</li><li>If successful, retrieve the CRM user roles and store the CRM systemuserid and roles in a GenericPrincipal object</li><li>If unsuccessful, throw an error</li></ol>
<p>Here is the overridden Validate method:</p>
<pre><code>///&lt;summary&gt;
/// Validate method to attempt to connect to CRM with supplied username/password and then execute a whoami request
/// &lt;/summary&gt;
/// &lt;param name="username"&gt;crm username&lt;/param&gt;
/// &lt;param name="password"&gt;crm password&lt;/param&gt;
public override void Validate(string username, string password)
{
	//get the httpcontext so we can store the user guid for impersonation later
	HttpContext context = HttpContext.Current;
	//if username or password are null, obvs we can't continue
	if (null == username || null == password)
	{
		throw new ArgumentNullException();
	}
	//get the crm connection using the simplified connection string method
	// the following assumes the server url is stored in the web.config appsettings collection like so:
	// &lt;add key="crmconnectionstring" value="Url=https://crm.example.com"/&gt;
	string connectionString = ConfigurationManager.AppSettings["crmconnectionstring"];
	connectionString += " Username=" + username + "; Password=" + password;
	Microsoft.Xrm.Client.CrmConnection connection = CrmConnection.Parse(connectionString);
	//try the whoami request
	//if it fails (user can't be authenticated, is disabled, etc.), the client will get a soap fault message
	using (OrganizationService service = new OrganizationService(connection))
	{
		try
		{
			WhoAmIRequest req = new WhoAmIRequest();
			WhoAmIResponse resp = (WhoAmIResponse)service.Execute(req);
			List&lt;string&gt; roles = GetUserRoles(resp.UserId, service);
			context.User = new GenericPrincipal(new GenericIdentity(resp.UserId.ToString()), roles.ToArray());
		}
		catch (System.ServiceModel.Security.MessageSecurityException ex)
		{
			throw new FaultException(ex.Message); 
		}
		catch (Exception ex)
		{
			throw new FaultException(ex.Message);
		}
	}
}</code></pre>
<p>And here is the GetUserRoles method called in the Validate method:</p>
<pre><code>/// &lt;summary&gt;
/// retrieves a list of CRM roles assigned to a specific user
/// &lt;/summary&gt;
/// &lt;param name="userid"&gt;&lt;/param&gt;
/// &lt;param name="service"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
private List&lt;string&gt; GetUserRoles(Guid userid, OrganizationService service)
{
	List&lt;string&gt; roles = new List&lt;string&gt;();
	string fetchXml = @"&lt;fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='true'&gt;
	 &lt;entity name='role'&gt;
		&lt;attribute name='name' /&gt;
		&lt;attribute name='businessunitid' /&gt;
		&lt;attribute name='roleid' /&gt;
		&lt;order attribute='name' descending='false' /&gt;
		&lt;link-entity name='systemuserroles' from='roleid' to='roleid' visible='false' intersect='true'&gt;
		 &lt;link-entity name='systemuser' from='systemuserid' to='systemuserid' alias='af'&gt;
			&lt;filter type='and'&gt;
			 &lt;condition attribute='systemuserid' operator='eq' uitype='systemuser' value='{$USERID}' /&gt;
			&lt;/filter&gt;
		 &lt;/link-entity&gt;
		&lt;/link-entity&gt;
	 &lt;/entity&gt;
	&lt;/fetch&gt;";
	fetchXml = fetchXml.Replace("$USERID", userid.ToString());
	EntityCollection results = service.RetrieveMultiple(new FetchExpression(fetchXml));
	foreach (Entity entity in results.Entities)
	{
		roles.Add((string)entity["name"]);
	}
	return roles;
}</code></pre>
<p>You can download the complete CrmUsernamePasswordValidator.cs class <a href="https://github.com/lucasalexander/Crm-Sample-Code/blob/master/misc-code-samples/CrmUsernamePasswordValidator.cs">here</a>.</p>
<p><strong>The service binding configuration</strong></p>
<p>A custom validator can work with WCF Transport, Message or TransportWithMessageCredential security. Inside the security element of your service binding in your web.config file, you must specify a clientCredentialType value of &quot;UserName.&quot;</p>
<p>Here's an example that uses a basicHttpBinding:</p>
<pre><code>&lt;basicHttpBinding&gt;
	&lt;binding name="BasicHttpEndpointBinding"&gt;
		&lt;security mode="TransportWithMessageCredential"&gt;
			&lt;message clientCredentialType="UserName"/&gt;
		&lt;/security&gt;
	&lt;/binding&gt;
&lt;/basicHttpBinding&gt;</code></pre>
<p>For more information on WCF service bindings and security modes, please see this overview from the Microsoft Patterns and Practices guide <a href="http://msdn.microsoft.com/en-us/library/ff648863.aspx" target="_blank">&quot;Improving Web Services Security: Scenarios and Implementation Guidance for WCF.&quot;</a></p>
<p><strong>The service behavior configuration</strong></p>
<p>The final step is to add a behaviors element to your web.config file that tells WCF to use the custom validator. Here is an example:</p>
<pre><code>&lt;behaviors&gt;
	&lt;serviceBehaviors&gt;
		&lt;behavior name="Behavior1" &gt;
			&lt;serviceCredentials&gt;
				&lt;userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomValidators.CrmUsernamePasswordValidator, CustomValidators" /&gt;
			&lt;/serviceCredentials&gt;
		&lt;/behavior&gt;
	&lt;/serviceBehaviors&gt;
&lt;/behaviors&gt;</code></pre>
<p>Note that &quot;Behavior1&quot; in line 3 should match the behaviorConfiguration attribute where you define the service. The customUserNamePasswordValidatorType is the name of your custom validator class and its assembly.</p>
<p><strong>Wrapping it up</strong></p>
<p>Once you're finished with these updates, your WCF service will now require the username and password to be supplied with inbound requests, and if the user can't be authenticated, a SOAP fault message will be returned. If you want to use the user's assigned CRM roles in your web service's business logic, you can check role membership using the HttpContext.Current.User.IsInRole method. You can also impersonate the user in subsequent calls to the Dynamics CRM Organization Service using the systemuserid value stored in the HttpContext.Current.User.Identity.Name field.</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[Introducing the Diesel Xrm Service Wrapper]]></title><description><![CDATA[<div class="kg-card-markdown"><p>In this post, I will present a generic Windows Communication Foundation (WCF) wrapper for the Dynamics CRM Organization Service that lets you turn any FetchXML query into a web service interface without needing to write any code at all. I call my solution the Diesel Xrm Service Wrapper after Diesel,</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/07/30/introducing-the-diesel-xrm-service-wrapper/</link><guid isPermaLink="false">5a5837226636a30001b976da</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[C#]]></category><category><![CDATA[web services]]></category><category><![CDATA[FetchXML]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Wed, 31 Jul 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>In this post, I will present a generic Windows Communication Foundation (WCF) wrapper for the Dynamics CRM Organization Service that lets you turn any FetchXML query into a web service interface without needing to write any code at all. I call my solution the Diesel Xrm Service Wrapper after Diesel, my Great Dane. Just like the CRM Organization Service, he's big and sometimes aggravating, so it's a perfect name!</p>
<p><img src="https://alexanderdevelopment.net/content/images/2013/07/diesel.jpg" alt="Diesel the Dynamics CRM Great Dane"></p>
<p>Usually I like to go into a lot of detail in my blog posts, but frankly WCF gives me such a headache that today I'm just going to explain how the things work at a high level and offer the solution for download without much commentary.</p>
<p>An administrator stores predefined FetchXML queries on the server where the service is hosted. The service's consumers all access a single endpoint, and a &quot;query&quot; parameter is used to load and execute the correct FetchXML query. The consumers authenticate using Dynamics CRM credentials, and a service account executes the queries while impersonating the calling user so that native Dynamics CRM security functionality authorizes all data requests.</p>
<h4 id="initialconfiguration">Initial Configuration</h4>
<p>First, download the solution here: <a href="https://alexanderdevelopment.net/content/images/2013/07/DieselXrmSvcWrapper.zip">DieselXrmSvcWrapper.zip</a> <em>(Updated Aug. 5, 2013 - This project is now hosted on <a href="http://lucasalexander.github.io/DieselXrmWrapper/">GitHub</a>. The original solution file download link in this post has been left unchanged, however.)</em></p>
<p>To configure the solution, you store the URL for your Dynamics CRM server and credentials for a user account to be used as a service account in the appSettings section of the web.config file. The service account should have fairly broad read permissions, including &quot;Act On Behalf Of Another User.&quot; You can also modify the WCF configuration if you want to use different bindings or security modes. In the solution download, I'm using a basicHttpBinding with a &quot;UserName&quot; message clientCredentialType (that's WCF-speak for HTTP basic authentication over SSL).</p>
<h4 id="querydefinition">Query Definition</h4>
<p>After you've finished the configuration, you can now create the FetchXML queries that will be used for the actual web service interfaces. The queries are stored in individual XML files in a specific directory on the web server, and when a web service consumer calls the service, the &quot;query&quot; parameter maps queries to requests.</p>
<p>In addition to predefined FetchXML, queries can contain paramter substitution placeholders in the format of {$PARAMETER_NAME} that will be replaced with values supplied by the web service consumer. Here's an example query that is stored in a file called contacts.xml:</p>
<pre><code>&lt;fetch version=&quot;1.0&quot; output-format=&quot;xml-platform&quot; mapping=&quot;logical&quot; distinct=&quot;false&quot;&gt;  
 &lt;entity name=&quot;contact&quot;&gt;  
 &lt;attribute name=&quot;fullname&quot; /&gt;  
 &lt;attribute name=&quot;contactid&quot; /&gt;  
 &lt;attribute name=&quot;ownerid&quot; /&gt;  
 &lt;attribute name=&quot;address1_stateorprovince&quot; /&gt;  
 &lt;attribute name=&quot;gendercode&quot; /&gt;  
 &lt;attribute name=&quot;createdon&quot; /&gt;  
 &lt;order attribute=&quot;fullname&quot; descending=&quot;false&quot; /&gt;  
 &lt;filter type=&quot;and&quot;&gt;  
 &lt;condition attribute=&quot;lastname&quot; operator=&quot;like&quot; value=&quot;{$lastnameletter}%&quot; /&gt;  
 &lt;/filter&gt;  
 &lt;/entity&gt;  
&lt;/fetch&gt; 
</code></pre>
<h4 id="samplesoapmessages">Sample SOAP Messages</h4>
<p>1<br>
Here's what the corresponding SOAP request method for the query above looks like:</p>
<pre><code>&lt;soapenv:Envelope   
 xmlns:soapenv=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;   
 xmlns:tem=&quot;http://tempuri.org/&quot;   
 xmlns:dies=&quot;http://schemas.datacontract.org/2004/07/DieselXrmSvcWrapper&quot;  
 xmlns:i=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;  
 &lt;soapenv:Header/&gt;  
 &lt;soapenv:Body&gt;  
 &lt;tem:Retrieve&gt;  
 &lt;tem:query&gt;contacts&lt;/tem:query&gt;  
 &lt;tem:inputParameters&gt;  
 &lt;!--Zero or more repetitions:--&gt;  
 &lt;dies:ParameterItem&gt;  
 &lt;dies:Name&gt;lastnameletter&lt;/dies:Name&gt;  
 &lt;dies:Value i:type=&quot;b:string&quot; xmlns:b=&quot;http://www.w3.org/2001/XMLSchema&quot;&gt;C&lt;/dies:Value&gt;  
 &lt;/dies:ParameterItem&gt;  
 &lt;/tem:inputParameters&gt;  
 &lt;/tem:Retrieve&gt;  
 &lt;/soapenv:Body&gt;  
&lt;/soapenv:Envelope&gt;  
</code></pre>
<p>The number of ParameterItems in the request should match the number of substitution placeholders in the query. If there are no placeholders, then you should omit the InputParameters section completely.</p>
<p>The SOAP response for the request above is attached here: <a href="https://alexanderdevelopment.net/content/images/2013/07/soap-response.txt">soap-response.txt</a>.</p>
<h4 id="wrappingup">Wrapping Up</h4>
<p>Now that you understand how the solution behaves and how to configure it, here's an overview of the solution components:</p>
<ol>
<li>FetchXML queries - As mentioned above, each query is stored in a separate XML file in a single directory. In my solution, the directory is called &quot;RetrieveQueries,&quot; but you can change it in the web.config file.</li>
<li>CrmUsernamePasswordValidator.cs - This custom username/password validator lets WCF validate the Dynamics CRM user credentials via TransportWithMessageCredential security. This also stores the users' CRM roles in an HttpContext.User object, so you could add some sort of role-based authorization to your service if you want.</li>
<li>SoapSvc.svc - This actually does the request/response processing.</li>
</ol>
<p>Once you have everything set up, you'll want to try it out, and I suggest using <a href="http://www.soapui.org">SoapUI</a>. To get up and running with SoapUI, you basically just point it at your service's auto-generated WSDL, and SoapUI will figure out most everything it needs to work. If you use my solution without modifying the WCF configuration, you will need to change the WSS-Password Type setting for your request to &quot;PasswordText,&quot; and you'll have to supply the username and password either in the request properties menu or on the Authorization tab. I've circled these fields in the screenshot below.</p>
<p><img src="https://alexanderdevelopment.net/content/images/2013/07/soap-ui.PNG#img-thumbnail" alt="SoapUI"></p>
<p>In the future, I plan to update the solution to handle create/update/delete requests, and I may look at setting up a REST interface, too. If you have any thoughts or feedback, please share in the comments.</p>
<p>Happy web service wrapping!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Accessing raw SOAP requests/responses from Dynamics CRM web services in C#]]></title><description><![CDATA[<div class="kg-card-markdown"><p>One of the things I have always found frustrating about WCF is that it effectively hides the actual SOAP message XML requests and responses in web service calls. From a Dynamics CRM perspective, I can think of at least three good reasons it would be nice to be able to</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/02/20/accessing-raw-soap-requests-responses-from-dynamics-crm-web-services-in-c/</link><guid isPermaLink="false">5a5837216636a30001b97663</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[C#]]></category><category><![CDATA[web services]]></category><category><![CDATA[XML]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Thu, 21 Feb 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>One of the things I have always found frustrating about WCF is that it effectively hides the actual SOAP message XML requests and responses in web service calls. From a Dynamics CRM perspective, I can think of at least three good reasons it would be nice to be able to access the raw XML generated and consumed by clients built with the SDK:</p>
<ol>
<li>Display retrieved results with XSL like I demonstrated in this client-side FetchXML example</li>
<li>Log the raw messages for QA, auditing or regulatory reasons</li>
<li>Process the XML to easily generate &quot;wrapper&quot; interfaces</li>
</ol>
<p>In this post I will show how to capture client requests and service responses for interfaces built with the CRM SDK as well as interfaces that use a WSDL-based proxy using a client message inspector.</p>
<p><strong>The message inspector class</strong></p>
<p>The easiest way to capture the actual SOAP messages is to use a client message inspector object (<a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageinspector.aspx">IClientMessageInspector</a>). The BeforeSendRequest and AfterReceiveReply methods of the client message inspector will give you the SOAP request and response as string objects that you can process however you want. Here is a class called MyInspector that stores requests and responses in list objects called sentMessages and receivedMessages respectively <a href="https://alexanderdevelopment.net/content/images/2013/02/MyInspector.cs.txt">MyInspector.cs (1.55 kb)</a>. The original source for this code is <a href="http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/fa3f4c55-5835-43f2-892f-737b4bccb598">http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/fa3f4c55-5835-43f2-892f-737b4bccb598</a>.</p>
<p><strong>Using the message inspector</strong></p>
<p>Once you have your message inspector ready, you have to have to update the behaviors for the destination endpoint to use it. If you are using the SDK, all you have to do is instantiate a new MyInspector object and then add it to your OrganizationServiceProxy's ServiceConfiguration.CurrentServiceEndpoint behaviors. The code below contains a helper function that creates a new OrganizationServiceProxy object and adds the message inspector.</p>
<pre><code>static OrganizationServiceProxy createProxy(string orgUri, string username, string password)  
{  
ClientCredentials credentials = new ClientCredentials();  
Uri organizationUri = new Uri(orgUri);  
  
IServiceConfiguration&lt;IOrganizationService&gt; config =  
ServiceConfigurationFactory.CreateConfiguration&lt;IOrganizationService&gt;(  
organizationUri);  
  
credentials.UserName.UserName = username;  
credentials.UserName.Password = password;  
  
OrganizationServiceProxy serviceProxy = new OrganizationServiceProxy(config, credentials);  
  
MyInspector inspector = new MyInspector();  
serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(inspector);  
  
return serviceProxy;  
}
</code></pre>
<p>If you are using WSDL-based proxy, adding the message inspector is slightly different, but just as simple. As with the SDK, you first have to instantiate a new MyInspector object, but you then add it to your WCF client's Endpoint.Behaviors object. The code below shows an version of the ExecuteWhoAmI method from the CRM SDK WsdlBasedProxies sample with the message inspector added.</p>
<pre><code>private static void ExecuteWhoAmI(ClientCredentials credentials, string serviceUrl)  
{  
using (OrganizationServiceClient client = new OrganizationServiceClient(&quot;CustomBinding_IOrganizationService&quot;,  
new EndpointAddress(serviceUrl)))  
{  
ApplyCredentials(client, credentials);  
MyInspector inspector = new MyInspector();  
client.Endpoint.Behaviors.Add(inspector);  
  
OrganizationRequest request = new OrganizationRequest();  
request.RequestName = &quot;WhoAmI&quot;;  
  
OrganizationResponse response = (OrganizationResponse)client.Execute(request);  
  
foreach (KeyValuePair&lt;string, object&gt; result in response.Results)  
{  
if (&quot;UserId&quot; == result.Key)  
{  
Console.WriteLine(&quot;User ID: {0}&quot;, result.Value);  
break;  
}  
}  
}  
}
</code></pre>
<p><strong>Accessing the messages</strong></p>
<p>Once you have added the message inspector to your endpoint behaviors, you are ready to call the CRM web service and access the request and response messages. Here is an updated version of the ExecuteWhoAmI method that writes the request and response messages to the console:</p>
<pre><code>private static void ExecuteWhoAmI(ClientCredentials credentials, string serviceUrl)  
{  
using (OrganizationServiceClient client = new OrganizationServiceClient(&quot;CustomBinding_IOrganizationService&quot;,  
new EndpointAddress(serviceUrl)))  
{  
ApplyCredentials(client, credentials);  
MyInspector inspector = new MyInspector();  
client.Endpoint.Behaviors.Add(inspector);  
  
OrganizationRequest request = new OrganizationRequest();  
request.RequestName = &quot;WhoAmI&quot;;  
  
OrganizationResponse response = (OrganizationResponse)client.Execute(request);  
  
foreach (KeyValuePair&lt;string, object&gt; result in response.Results)  
{  
if (&quot;UserId&quot; == result.Key)  
{  
Console.WriteLine(&quot;User ID: {0}&quot;, result.Value);  
break;  
}  
}  
  
Console.WriteLine(&quot;****REQUEST****&quot;);  
foreach (string sent in inspector.sentMessages)  
{  
Console.WriteLine(sent);  
Console.WriteLine();  
  
}  
  
Console.WriteLine(&quot;****RESPONSE****&quot;);  
foreach (string received in inspector.receivedMessages)  
{  
Console.WriteLine(received);  
Console.WriteLine();  
}  
Console.ReadLine();  
}  
}
</code></pre>
</div>]]></content:encoded></item><item><title><![CDATA[Misadventures with CRM 2011 web services and ADFS]]></title><description><![CDATA[<div class="kg-card-markdown"><p>I think the Dynamics CRM 2011 SDK is swell for interoperability, but I wanted to get a closer look at how the actual web service calls work, so I decided to access the sandbox CRM instance my company provides using a WSDL-based proxy as described <a href="http://msdn.microsoft.com/en-us/library/gg509052.aspx">here</a>. Because the SDK has</p></div>]]></description><link>https://alexanderdevelopment.net/post/2013/02/16/misadventures-with-crm-2011-web-services-and-adfs/</link><guid isPermaLink="false">5a5837216636a30001b9766a</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 2011]]></category><category><![CDATA[programming]]></category><category><![CDATA[C#]]></category><category><![CDATA[web services]]></category><category><![CDATA[XML]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Sun, 17 Feb 2013 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>I think the Dynamics CRM 2011 SDK is swell for interoperability, but I wanted to get a closer look at how the actual web service calls work, so I decided to access the sandbox CRM instance my company provides using a WSDL-based proxy as described <a href="http://msdn.microsoft.com/en-us/library/gg509052.aspx">here</a>. Because the SDK has several examples for connecting to CRM instances using different kinds of authentication in the SDK\SampleCode\CS\WsdlBasedProxies directory, I figured this would be a piece of cake. As it turns out, I was wrong.</p>
<p><em>Disclaimer: before asking anyone read through to the end of this post, let me say I think the problem I ran into may be fairly specific to my organization's ADFS setup because despite a lot of web searches, I couldn't find anything that specifically addressed my issue from a Dynamics CRM perspective. On the other hand, if you are having the same problem I did, maybe this post will save you some time.</em></p>
<p>Because my CRM sandbox instance is an Internet-facing (IFD) deployment, I looked at the ifd project in the SDK's wsdlbasedproxies solution and followed the setup instructions. I ran into a problem almost immediately. After creating service references for the Discovery and Organization services, the next instruction is:</p>
<blockquote>
<p>In the &quot;<binding name="CustomBinding_IOrganizationService">&quot; node, locate the &quot;&lt;issuer ...&gt;&quot; node. This node allows the user to specify which Issuer should be used when issuing a token. The various STS endpoints will be present in the commented out &quot;alternativeIssuedTokenParameters&quot; node. In my example, UserNameMixed is used. In order to use UserNameMixed, the &quot;binding&quot; and &quot;bindingConfiguration&quot; attributes need to be updated to match the node in &quot;alternativeIssuedTokenParameters&quot;. The easiest way to find this endpoint is to search for &quot;<a href="https://adfs.contoso.com:555/adfs/services/trust/13/usernamemixed">https://adfs.contoso.com:555/adfs/services/trust/13/usernamemixed</a>&quot;. In the generated configuration file, you'll find: <issuer address="https://adfs.contoso.com:555/adfs/services/trust/13/usernamemixed" bindingconfiguration="https://adfs.contoso.com:555/adfs/services/trust/13/usernamemixed" binding="ws2007HttpBinding"> Copy this node and replace the current issuer node in the &quot;<binding name="CustomBinding_IOrganizationService">&quot; node.</binding></issuer></binding></p>
</blockquote>
<p>Well, in my app.config file, there was no alternativeIssuedTokenParameters node. All I had was these two elements in my CustomBinding_IOrganizationService and CustomBinding_IDiscoveryService bindings:</p>
<pre><code>&lt;issuer address=&quot;http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous&quot; /&gt;  
&lt;issuerMetadata address=&quot;https://ADFS.SOMEDOMAIN.COM/adfs/services/trust/mex&quot; /&gt;
</code></pre>
<p>I figured what the heck, let's try to run the sample in debug mode anyway and see if it works. Spoiler alert: it didn't. Instead of connecting to CRM, I got a Windows CardSpace (never heard of it before) screen pop up asking me if I wanted to send a card to the site. Seeing as the SDK readme doc had made of mention of CardSpace, I figured something must be misconfigured, so I closed the window and stopped debugging.</p>
<p>It took me a while to figure it out (I'm a developer, not a networking guy), but I finally realized that my WCF client knew it should be using a token from the SOMEDOMAIN.COM STS to talk to CRM, but it didn't know how to get one. After some fruitless searching, I stumbled upon a post by the MCS UK dev team called &quot;<a href="http://blogs.msdn.com/b/mcsuksoldev/archive/2011/08/17/federated-security-how-to-setup-and-call-a-wcf-service-secured-by-adfs-2-0.aspx">Federated Security: How to setup and call a WCF service secured by ADFS 2.0.</a>&quot; At first I looked at programmatically getting a token, but then I decided it would be much simpler to take the config-based approach described in this MSDN tutorial: <a href="http://msdn.microsoft.com/en-us/gg557876">http://msdn.microsoft.com/en-us/gg557876</a>. Also, the config-based approach is what should have been happening in the SDK sample anyway.</p>
<p>To get the issuer element of my bindings right, I first created a service reference for the address in the issuerMetadata element. As soon as I did, my app.config file was updated with lots of binding and endpoints that looked like what was described in the SDK sample setup file, so I figured I must be on the right track.</p>
<p>Knowing that my sandbox CRM instance used the &quot;/adfs/services/trust/13/username&quot; endpoint for getting a token from the ADFS STS (thanks to watching Fiddler while a desktop application that uses the SDK connected to my CRM instance), I searched in the updated app.config file for that string, and I found this element:</p>
<pre><code>&lt;endpoint address=&quot;http://ADFS.SOMEDOMAIN.COM/adfs/services/trust/13/username&quot;  
binding=&quot;ws2007HttpBinding&quot; bindingConfiguration=&quot;UserNameWSTrustBinding_IWSTrust13Async&quot;  
contract=&quot;STS.IWSTrust13Async&quot; name=&quot;UserNameWSTrustBinding_IWSTrust13Async&quot;&gt;  
&lt;identity&gt;  
&lt;certificate encodedValue=&quot;REALLY_LONG_CERTIFICATE_STRING...&quot; /&gt;  
&lt;/identity&gt;  
&lt;/endpoint&gt;
</code></pre>
<p>Next, I commented out the existing issuer and issuerMetadata elements in my CRM service bindings and replaced them with the address, binding, binding configuration and identity details from the STS endpoint like so:</p>
<pre><code>&lt;issuer address=&quot;http://ADFS.SOMEDOMAIN.COM/adfs/services/trust/13/username&quot; binding=&quot;ws2007HttpBinding&quot; bindingConfiguration=&quot;UserNameWSTrustBinding_IWSTrust13Async&quot; &gt;  
&lt;identity&gt;  
&lt;certificate encodedValue=&quot;REALLY_LONG_CERTIFICATE_STRING...&quot; /&gt;  
&lt;/identity&gt;  
&lt;/issuer&gt;
</code></pre>
<p>After that, I ran the sample project in debug mode, and it worked perfectly.</p>
<p><strong>Why did this happen?</strong></p>
<p>I will readily admit I don't understand the ins and outs of ADFS. I get the point of it and the basics of how it works, but I certainly don't know why the configuration of my CRM instance would lead to these results. All I can say at this point is that I'm glad I've got it working, and I'll know what to do in the future if a problem like this ever comes up again.</p>
</div>]]></content:encoded></item></channel></rss>