tag:blogger.com,1999:blog-71788022065945417962024-03-13T17:50:18.659+00:00No Intelligent LifeCharles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.comBlogger88125tag:blogger.com,1999:blog-7178802206594541796.post-42250782087347272372016-05-19T21:46:00.000+01:002016-05-19T21:46:53.117+01:00Deploy Word document generation template to new Dynamics 2016 environment.Microsoft are treating the new document generation facility in Dynamics 2016 as the best thing since sliced bread. There are some genuine limitations with it at the moment which I've seen posted elsewhere.<br />
But I've come across an issue with custom entities. I managed to create a template alright but then tried to install it in another environment. I wasn't trying anything fancy, just a manual install of the template. But when I added the template it bound it to the wrong entity. Now it doesn't offer me the option to choose the entity, just goes ahead and binds it to the wrong thing.<br />
It is to due to the object type code or sometimes called the entity type code. That code is fixed for all the standard entities, but custom entities are given a number in the 10,000 range. What I've discovered is this number is not the same across environments. It's not that I've been stupid and manually created the entity, I deployed a solution as you normally do, but it issues a different type code in the new environment. You can see it easily if you can access the full url for an entity record, you know when you want to find the unique guid. The etc parameter is the entity type code.<br />
Now this wouldn't be a problem except when you create a Word document template it adds the entity type code to the end of the namespace. you can see it when in Word and you are in the Xml mapping pane. It's there at the end of the urn. That then causes it to bind to the wrong entity when deployed into the new environment.<br />
If you spent hours creating the template you don't want to have to repeat this in each environment.<br />
To solve it, take the template and rename the extension from docx to zip. You will see in the extract a customxml folder and in there a file that contains the urn of the source data. You have to change the etc at the end to match the correct one in the target environment. Change any other related custom entities. Zip it back up and rename it back to docx. Load it back into the target environment and it should work. Maybe I'll find the time to write an app to do this for me because I don't see Microsoft fixing this anytime soon. Damn, sometimes Microsoft just don't think things through.Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com2tag:blogger.com,1999:blog-7178802206594541796.post-82529840547229238532016-05-13T18:07:00.000+01:002016-05-13T18:07:04.733+01:00Retrieving the Message from Service Bus QueueThis is a follow up to the previous post where I sent a strongly typed XML message from a CRM plugin to a Service Bus Queue. This is what the Xml looks like that I sent to the queue.<br />
Note that the root node is the name of the entity. This is a snippet to show the attributes and then the formatted values. You can easily manipulate the Xml by changing the way it populates the datatable.<br />
<br />
<contact><br />
<attributes><br />
<address1_addressid>c6fd930f-512a-42fb-a645-af4a672c740f</address1_addressid><br />
<address2_addressid>6a280e36-c009-463b-84f1-8666c2dfc5ba</address2_addressid><br />
<address2_addresstypecode>1</address2_addresstypecode><br />
<address2_freighttermscode>1</address2_freighttermscode><br />
<address2_shippingmethodcode>1</address2_shippingmethodcode><br />
<address3_addressid>5475a20e-3c79-479a-a1d5-05b0f144a8fc</address3_addressid><br />
<contactid>1d50bcf0-2519-e611-80da-5065f38b46e1</contactid><br />
<createdby>Charles Emes</createdby><br />
<createdon>13/05/2016 16:15:51</createdon><br />
;... more attributes<br />
;... now the formatted values<br />
<address2_addresstypecodename>Default Value</address2_addresstypecodename><br />
<address2_freighttermscodename>Default Value</address2_freighttermscodename><br />
<address2_shippingmethodcodename>Default Value</address2_shippingmethodcodename><br />
<createdonname>13/05/2016 17:15</createdonname><br />
</attributes></contact><br />
<br />
What I'm missing is a namespace and that is easy enough to add once I load it into an XmlDocument. I'm a BizTalk developer so right now I'm happy with a message that I can transform into anything I want. The attributes are in alphabetical order so I can cope with missing attributes easily enough in the XSD by making Nillable=true and MinOccurs=0. But I can also deserialize this into a contact object by creating a class form the XSD using the XSD.EXE. Note this is absolutely not a CRM Contact object but my own object. Check out my usings because there is no Microsoft.Xrm.SDK anywhere to be seen. <br />
<br />
This receiver is just a console app and I ripped the code from another blogger. I'm just using it show what you can do with the message now you've got it. <br />
<br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">static</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">void</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> Main(</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">string</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">[] args)</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
{<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">string</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> connectionString = </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">CloudConfigurationManager</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.GetSetting(</span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">"Microsoft.ServiceBus.ConnectionString"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">QueueClient</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> Client = </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">QueueClient</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.CreateFromConnectionString(connectionString, </span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">"anoqueue"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">//Console.WriteLine("\nReceiving message from Queue...");</span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">BrokeredMessage</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> message = </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">null</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">NamespaceManager</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> namespaceManager = </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">NamespaceManager</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.Create();</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">while</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> (</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">true</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">)</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
{<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">try</span></span></span><br />
<span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> {<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">//receive messages from Queue </span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> message = Client.Receive(</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">TimeSpan</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.FromHours(10));</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">if</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> (message != </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">null</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">)</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
{<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">Console</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.WriteLine(</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">string</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.Format(</span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">"Message received: Id = {0}"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">, message.MessageId));</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">string</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> s = </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">new</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">StreamReader</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">(message.GetBody<</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">Stream</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">>(), </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">Encoding</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.ASCII).ReadToEnd();</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">// load into an XML Document to s</span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System.Xml.</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">XmlDocument</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> xmldoc = </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">new</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System.Xml.</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">XmlDocument</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">();</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
xmldoc.LoadXml(s);<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">// need to add a namespace because it doesn't have one</span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> xmldoc.DocumentElement.SetAttribute(</span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">"xmlns"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">, </span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">"http://xrm.generic.schemas"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">string</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> mydocpath = </span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">@"C:\Projects\Test\ReceiveFromSB\"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> xmldoc.Save(mydocpath + </span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">"saved.xml"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">// Deserialize to an object too</span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">XmlRootAttribute</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> xRoot = </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">new</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">XmlRootAttribute</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">();</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> xRoot.ElementName = message.Properties[</span></span><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;"><span style="color: #a31515; font-family: "consolas"; font-size: x-small;">"EntityName"</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">].ToString();</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">XmlSerializer</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> serializer = </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">new</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">XmlSerializer</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">(</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">typeof</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">(</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">contact</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">),xRoot);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">StringReader</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> rdr = </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">new</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">StringReader</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">(s);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">contact</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> myContact = (</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">contact</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">)serializer.Deserialize(rdr);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">// Now delete the message</span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> message.Complete();<br />
<br />
}<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">else</span></span></span><br />
<span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> {<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">//no more messages in the queue </span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">break</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
}<br />
}<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">catch</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> (</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">MessagingException</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> me)</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
{<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">if</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> (!me.IsTransient)</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
{<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">Console</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.WriteLine(me.Message);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">throw</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
}<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">else</span></span></span><br />
<span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> {<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">// HandleTransientErrors(e);</span></span></span><br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;">
</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> }<br />
}<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">catch</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> (</span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">Exception</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> e)</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
{<br />
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;"><span style="color: #2b91af; font-family: "consolas"; font-size: x-small;">Console</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">.WriteLine(e.Message);</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> </span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">throw</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
}<br />
}<br />
Client.Close(); <br />
}</span></span>}<br />
</span>Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-90050725106351464372016-05-13T17:29:00.003+01:002016-05-13T18:06:51.584+01:00Dynamics CRM Online: Posting Messages to the Azure Service BusI have to say I've never really liked the way Dynamics CRM integrates with the Azure Service Bus. I've posted on this before <a href="https://www.blogger.com/blogger.g?blogID=7178802206594541796#editor/target=post;postID=2910504101371340612;onPublishedMenu=allposts;onClosedMenu=allposts;postNum=9;src=postname" target="_blank">here</a> and <a href="https://www.blogger.com/blogger.g?blogID=7178802206594541796#editor/target=post;postID=4333062957897519947;onPublishedMenu=allposts;onClosedMenu=allposts;postNum=10;src=postname" target="_blank">here</a>. What I dislike is the way it posts the Context to the Service Bus. In order to do anything with the Context I need to use the RemotePluginContext and then extract the entity that I want. That means using the XrmSDK and being familiar with the way to handle the Context. But I like a loosely coupled architecture. I would expect a CRM plugin to place a strongly typed Xml message on the Service Bus. Then processing of the message requires no knowledge of CRM. I'm a BizTalk developer and for interfaces are always about messages that comply with XML schemas because that acts as the contract. In a development environment where you have different teams of developers with different skill sets this separation I believe is vital. <br />
<br />
Now you may know that Dynamics CRM only supports the ACS authentication of the Service Bus and you have to create this using PowerShell commands because it is not possible via the portal. See this post. You can find the details of setting up the Service Endpoint elsewhere but the bottom line is that you are using a Guid that points to the Service Endpoint record. So what about deploying to another environment where you will use a different Service Endpoint? Well you have to go through the manual process again. What in a Production environment? Are you kidding me? No, I want to be able to deploy and then just configure the endpoint url. <br />
<br />
The challenge in doing this online is that the plugin runs in Sandbox mode and it restricts what .Net assemblies I can use, System.Security being one of them. That rules out SAS authentication because it requires on System.Security.Cryptography. <br />
<br />
My solution is a plugin that does two things. It populates a data table with the attributes from the entity and produces strongly typed Xml. It then uses WebClient to POST the xml as a string to the Service Bus using the REST API. The authentication uses the ACS token and the only configuration parameters I need are the service bus namespace, the queue name, and the issuer secret. The great thing about the solution is it is totally generic, it works with any entity, all you need is to configure a plugin step. A couple of points to note. <br />
1. I'm using a queue.<br />
2. My plugin is registered as synchronous because I want to maintain ordered delivery<br />
3. I'm sending to the queue synchronously, because I want to know I successfully sent it.<br />
4. I can choose if I want to use the PreImage, PostImage or Target<br />
5.The plugin calls my EntitySerialize class<br />
6. I am indebted to other bloggers for much of this code<br />
<br />
The next post shows you can retrieve the message form the queue.<br />
<span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">using</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"></span></span></span><br />
<span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">using</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System.Collections.Specialized;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">using</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System.Data;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">using</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System.Linq;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">using</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System.Text;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">using</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> System.Net;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;">
</span></span><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;"><span style="color: blue; font-family: "consolas"; font-size: x-small;">using</span></span></span><span style="font-family: "consolas"; font-size: x-small;"><span style="font-family: "consolas"; font-size: x-small;"> Microsoft.Xrm.Sdk;</span></span><br />
<br />
public class EntityHelper<br />
{<br />
// **************Use bits from the Service bus namespace below ******************<br />
//<br />
static string ServiceNamespace = "yournamespace";<br />
static string ServiceHttpAddress = "<a href="https://yournamespace.servicebus.windows.net/queuename/messages">https://yournamespace.servicebus.windows.net/queuename/messages</a>";<br />
const string acsHostName = "accesscontrol.windows.net";<br />
const string sbHostName = "servicebus.windows.net";<br />
const string issuerName = "owner";<br />
const string issuerSecret = "your_issuer_secret_goes_here";<br />
public static void EntitySerialize(ITracingService tracingService, IOrganizationService service, Entity entity, string orgName, string msgName, string correlation)<br />
{<br />
try<br />
{<br />
DataSet ds = new DataSet(entity.LogicalName);<br />
DataTable dt = new DataTable("attributes");<br />
DataTable dataTable = new DataTable();<br />
ConvertEntityToDataTable(dt, entity);<br />
ds.Tables.Add(dt);<br />
string xml = ds.GetXml();<br />
PostMessageToBus(entity, orgName, msgName, correlation, xml);<br />
}<br />
catch (System.Net.WebException we)<br />
{<br />
tracingService.Trace(we.Message);<br />
throw new Exception("Web Exception: " +we.Message);<br />
}<br />
catch (Exception e)<br />
{<br />
tracingService.Trace(e.Message);<br />
throw e;<br />
}<br />
return ;<br />
}<br />
private static void PostMessageToBus(Entity entity, string orgName, string msgName, string correlation, string xml)<br />
{<br />
WebClient webClient = new WebClient();<br />
webClient.Headers[HttpRequestHeader.Authorization] = GetToken();<br />
webClient.Headers[HttpRequestHeader.ContentType] = "application/atom+xml;type=entry;charset=utf-8";<br />
// Set brokered Properties this way<br />
webClient.Headers.Add("BrokerProperties", "{ \"MessageId\":\"123456789\", \"Label\":\"M1\"}");<br />
// example of the parameters that can be passed and available to receiver as mesage.Properties collection<br />
webClient.Headers["Correlation"] = correlation;<br />
webClient.Headers["OrganisationName"] = orgName;<br />
webClient.Headers["MessageName"] = msgName;<br />
webClient.Headers["EntityName"] = entity.LogicalName;<br />
var response = webClient.UploadData(ServiceHttpAddress, "POST", System.Text.Encoding.UTF8.GetBytes(xml));<br />
string responseString = Encoding.UTF8.GetString(response);<br />
}<br />
///////<br />
private static void ConvertEntityToDataTable(DataTable dataTable, Entity entity)<br />
{<br />
DataRow row = dataTable.NewRow();<br />
foreach (var attribute in entity.Attributes.OrderBy(a=>a.Key))<br />
{<br />
if (!dataTable.Columns.Contains(attribute.Key))<br />
{<br />
dataTable.Columns.Add(attribute.Key);<br />
}<br />
if (getAttributeValue(attribute.Value) != null)<br />
{<br />
row[attribute.Key] = getAttributeValue(attribute.Value).ToString();<br />
}<br />
}<br />
foreach (var fv in entity.FormattedValues.OrderBy(a=>a.Key))<br />
{<br />
if (!dataTable.Columns.Contains(fv.Key + "name"))<br />
{<br />
dataTable.Columns.Add(fv.Key + "name");<br />
}<br />
row[fv.Key + "name"] = fv.Value;<br />
}<br />
dataTable.Rows.Add(row);<br />
}<br />
///////<br />
private static object getAttributeValue(object entityValue)<br />
{<br />
object output = "";<br />
switch (entityValue.ToString())<br />
{<br />
case "Microsoft.Xrm.Sdk.EntityReference":<br />
output = ((EntityReference)entityValue).Name;<br />
break;<br />
case "Microsoft.Xrm.Sdk.OptionSetValue":<br />
output = ((OptionSetValue)entityValue).Value.ToString();<br />
break;<br />
case "Microsoft.Xrm.Sdk.Money":<br />
output = ((Money)entityValue).Value.ToString();<br />
break;<br />
case "Microsoft.Xrm.Sdk.AliasedValue":<br />
output = getAttributeValue(((Microsoft.Xrm.Sdk.AliasedValue)entityValue).Value);<br />
break;<br />
default:<br />
output = entityValue.ToString();<br />
break;<br />
}<br />
return output;<br />
}<br />
private static string GetToken()<br />
{<br />
var acsEndpoint = "https://" + ServiceNamespace + "-sb." + acsHostName + "/WRAPv0.9/";<br />
// Note that the realm used when requesting a token uses the HTTP scheme, even though<br />
// calls to the service are always issued over HTTPS<br />
var realm = "http://" + ServiceNamespace + "." + sbHostName + "/";<br />
NameValueCollection values = new NameValueCollection();<br />
values.Add("wrap_name", issuerName);<br />
values.Add("wrap_password", issuerSecret);<br />
values.Add("wrap_scope", realm);<br />
WebClient webClient = new WebClient();<br />
byte[] response = webClient.UploadValues(acsEndpoint, values);<br />
string responseString = Encoding.UTF8.GetString(response);<br />
var responseProperties = responseString.Split('&');<br />
var tokenProperty = responseProperties[0].Split('=');<br />
var token = Uri.UnescapeDataString(tokenProperty[1]);<br />
return "WRAP access_token=\"" + token + "\"";<br />
}<br />
<br />
} <br />
}Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com4tag:blogger.com,1999:blog-7178802206594541796.post-7845841411246542702016-04-22T18:05:00.001+01:002016-04-22T18:05:25.040+01:00Sharing the Host WiFi with Hype-V imageI use Hyper-V for all of my development work. Up until now I've been providing internet access to my Hyper-V images by setting up a Virtual Switch in Hyper-V, and configuring it as an Internal network. When my host is connected to the internet, I use Internet Connection Sharing to this Virtual Switch. I then configure the Hyper-V images to use a legacy adapter and select this Virtual Switch. Here is how my WiFi adapter is shared.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3-rgMrqM8p7buDONgp2aFHu6Vu7PZSYSTLVz3MgqUWW_ptsKGJ7AgUImJEWRT2A421GlodnV41zZdoP7V4bokQO5K7aQQRJqNcsXvBMnaJcSIggawh3DTrKZ_MITZvZ0s7z3WhuHbZgM/s1600/InternetConnection+Sharing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3-rgMrqM8p7buDONgp2aFHu6Vu7PZSYSTLVz3MgqUWW_ptsKGJ7AgUImJEWRT2A421GlodnV41zZdoP7V4bokQO5K7aQQRJqNcsXvBMnaJcSIggawh3DTrKZ_MITZvZ0s7z3WhuHbZgM/s320/InternetConnection+Sharing.png" width="275" /></a></div>
<a href="https://www.blogger.com/" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a>This procedure is well documented in other posts. But it has a snag. Internet Connection Sharing insists on using IP addresses in the 192.168.0.* range and your WiFi router must use an alternative IP address range e.g. 192.168.1.* <br />
<br />
I recently upgraded my Virgin broadband and the new router was using the IP range 192.168.0.* You could supposedly change it but I could not get this to work properly so I started to hunt around for another solution that would leave the IP range unchanged. I stumbled on the wonderful network bridge.<br />
<br />
The solution is the go into Virtual Switch settings and create a new Virtual Switch but select External network. I selected my WiFi network card from the list and enabled "Allow management operating system to share this network adapter". <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3K6NZpDmvMR16w_4VnnNQSxUNQyE74bQcXIwiN-uHPOr24UTXy4fg3pFCxMHpO6Xc9XaagYx4nhbr4UHxtUONmjVp4aqgmXm9KMSPv4WxwvfV21qF5H9zLKz41wmQnzeseYe3Ot3J-Xw/s1600/Hyper-V.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3K6NZpDmvMR16w_4VnnNQSxUNQyE74bQcXIwiN-uHPOr24UTXy4fg3pFCxMHpO6Xc9XaagYx4nhbr4UHxtUONmjVp4aqgmXm9KMSPv4WxwvfV21qF5H9zLKz41wmQnzeseYe3Ot3J-Xw/s320/Hyper-V.png" width="320" /></a></div>
<br />
<br />
When you click OK, it takes a minute but what its doing is creating a Network Bridge in your Network Connections along with a Hyper-V Virtual Ethernet adapter you are probably familiar with. My virtual machines use the same approach, a legacy adapter that is configured for this external Virtual Switch. <br />
<br />
<a href="https://www.blogger.com/" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a>Now when I look at my Network Connections its a bit odd. My WiFi adapter displays Enabled, Bridged even when I am not connected to the Internet. When I make the connection in the usual way it is the Hyper-V Virtual adapter that goes through the whole Identifying... stage until it connects. It looks counter-intuitive but it works a treat. So that's it. My Hyper-V images are connected to the Internet and I didn't have to change the IP address of the router. <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://www.blogger.com/" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><img border="0" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyREKQuSgOf0VZB_zX6vXC4GIH09-yBda5HaiUyt7NlOGrHOe-buvXOWF5cgEWiYi1SrumDTbG6MUECpY6XvJGemgJxa0CC-BE36_fslnbrdDZOv3gRnpCIcrmG1UmoSm4OU21LIvl-aU/s320/NetworkAdapters.png" width="320" /></div>
Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-89396558043256849422016-04-15T17:19:00.001+01:002016-04-19T09:24:19.581+01:00Dynamics CRM 2016 and Use Legacy form renderingSo you may know that Microsoft has improved form load by doing some extensive caching. There is a setting under General Settings called "Use Legacy form rendering" which you can set to Yes or No. <br />
<br />
Now you might wonder why I am writing a post about this setting. Well it was a JavaScript error on a Form Load that I was getting. I had my own JavaScript code on the Form Load but the error shown was confusing:<br />
Field:window<br />
Event:onload<br />
Error:Unable to get property '$o_3' of undefined or null reference<br />
<br />
Huh? A bit of Googling showed that others had come across it to<br />
<br />
<div class="MsoNormal" style="margin: 0cm 0cm 0pt;">
<a href="https://patricda.wordpress.com/2015/09/18/jscript-unable-to-get-property-o_3-of-undefined-or-null-reference-crm-2015-update1-0/"><span style="color: #0563c1; font-family: "calibri";">https://patricda.wordpress.com/2015/09/18/jscript-unable-to-get-property-o_3-of-undefined-or-null-reference-crm-2015-update1-0/</span></a><o:p></o:p></div>
<br />
The post included this comment "Note that this error only occurs when you turn <strong>on</strong> the “Use Legacy form rendering”. Sure enough changing this setting to No avoids the error. <br />
<br />
But what if you want to preserve the faster form rendering? Patric provide the solution in his blog. <br />
Add the following line before calling the prefilter function.<br />
<br />
<span class="skimlinks-unlinked">Xrm.Page.getControl(“EntityName”)._control</span> && <span class="skimlinks-unlinked">Xrm.Page.getControl(“EntityName”)._control.tryCompleteOnDemandInitialization</span> && <span class="skimlinks-unlinked">Xrm.Page.getControl(“EntityName”)._control.tryCompleteOnDemandInitialization</span>();<br />
<br />
Brilliant. Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-54870466366168727032016-04-15T17:08:00.000+01:002016-04-15T17:08:36.122+01:00Dynamics CRM 2016 and Legacy EntitiesThis is not the first time I've run into a problem with so called "Legacy Entities". I am referring to the entities that have been left out in the cold since CRM 2013. These include<br />
<ul>
<li>address</li>
<li>opportunity product</li>
<li>quote product</li>
<li>order product</li>
<li>invoice product</li>
</ul>
<br />
There are some things that these entities don't support which include<br />
<ul>
<li>Accessible in the Tablet App</li>
<li>Update attributes with workflows</li>
<li>Business Rules (though oddly Opportunity product does support business rules)</li>
<li>Old style forms</li>
</ul>
<br />
I have also come across with problems when upgrading to CRM 2016. This problem occurred on Opportunity Products form which had been customised in CRM 2015. I removed a number of fields I didn't need and it was working fine. <br />
After the upgrade to 2016 though I was getting this JavaScript error on form load<br />
<br />
Field:window<br />
Event:onload<br />
Error:Unable to get property 'addOnChange' of undefined or null reference<br />
<br />
Now that was not from any JavaScript code that I had but from a Microsoft library called OpportunityProduct_main_system_library.js<br />
<br />
When I looked into the code I could see that it was referring to attributes that were not on the form:<br />
Manual discount amount<br />
Tax<br />
<br />
When I added these back onto the form and hid them, the error went away. <br />
<br />
Moral of the story: Don't delete attributes from legacy forms - just hide them. Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com1tag:blogger.com,1999:blog-7178802206594541796.post-72400103851759039612015-12-12T15:36:00.003+00:002015-12-12T15:37:42.391+00:00Dependent (Linked) OptionSets in Dynamics CRM 2015I recently used the sample code provided in the SDK that allows you to have multiple OptionSets linked together so that selecting an item in the first OptionSet will filter the items appearing in the second. <br />
<br />
<a href="https://msdn.microsoft.com/en-us/library/gg594433(v=crm.7).aspx">https://msdn.microsoft.com/en-us/library/gg594433(v=crm.7).aspx</a><br />
<br />
There was an error in the instructions for configuring the OnLoad event on the form. It says to use<br />
<br />
<span style="font-family: "courier new";">"sample_TicketDependentOptionSetConfig.xml"</span><br />
<span style="font-family: "courier new";"></span><br />
as a parameter. That's wrong. You need to use <br />
<br />
<span style="font-family: "courier new";">"sample_TicketDependentOptionSetConfig"</span><br />
<span style="font-family: "courier new";"></span><br />
The SDK.DependentOptionSet.init function in the JavaScript file I modified slightly to support multiple languages. The first few lines now read<br />
<br />
<span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: x-small;"><span style="color: green; font-family: "consolas"; font-size: small;">//Retrieve the XML Web Resource specified by the parameter passed</span></span><span style="font-size: small;"></span> </span><span style="color: blue; font-family: "consolas";"><span style="color: blue; font-family: "consolas";"><span style="color: blue; font-family: "consolas";">var</span></span></span><span style="font-family: "consolas";"><span style="font-family: "consolas";"> clientURL = Xrm.Page.context.getClientUrl();</span></span><br />
<span style="font-family: "consolas";"><span style="font-family: "consolas";">
</span></span><br />
<span style="font-family: "consolas";"><span style="font-family: "consolas";"> </span></span><span style="color: blue; font-family: "consolas";"><span style="color: blue; font-family: "consolas";"><span style="color: blue; font-family: "consolas";">var</span></span></span><span style="font-family: "consolas";"><span style="font-family: "consolas";"> userLcid = Xrm.Page.context.getUserLcid();</span></span><br />
<span style="font-family: "consolas";"><span style="font-family: "consolas";">
</span></span><br />
<span style="font-family: "consolas";"><span style="font-family: "consolas";"> </span></span><span style="color: blue; font-family: "consolas";"><span style="color: blue; font-family: "consolas";"><span style="color: blue; font-family: "consolas";">var</span></span></span><span style="font-family: "consolas";"><span style="font-family: "consolas";"> pathToWR = clientURL + </span></span><span style="color: #a31515; font-family: "consolas";"><span style="color: #a31515; font-family: "consolas";"><span style="color: #a31515; font-family: "consolas";">"/WebResources/"</span></span></span><span style="font-family: "consolas";"><span style="font-family: "consolas";"> + webResourceName + </span></span><span style="color: #a31515; font-family: "consolas";"><span style="color: #a31515; font-family: "consolas";"><span style="color: #a31515; font-family: "consolas";">"_"</span></span></span><span style="font-family: "consolas";"><span style="font-family: "consolas";"> + userLcid;</span></span><br />
<span style="font-family: "consolas"; font-size: x-small;"></span><br />
<span style="font-family: "consolas"; font-size: x-small;"></span><br />
<span style="font-family: "consolas"; font-size: x-small;"></span><br />
<span style="font-family: "consolas"; font-size: x-small;"></span><br />
The data files were then appended with the relevant LCID for each language <br />
<br />
e.g. <span style="font-family: "courier new";">"sample_TicketDependentOptionSetConfig_1033.xml"</span><br />
<br />
A very cool and easy to use JavaScript Library. Thanks Microsoft. <br />
<span style="font-family: "consolas"; font-size: x-small;"></span><br />Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-5023119273091761232015-11-29T20:03:00.001+00:002015-11-29T20:03:18.413+00:00ILMerge Command Line SyntaxI had cause the other day to use ILMerge to combine several DLLs. The first issue I came across was:<br />
<br />
Unresolved assembly reference not allowed: System.Core.<br />
<br />
This is mentioned in several blogs and the solution suggested was to use the /lib switch and specify the path to the .NET library you want for the target. In my case I wanted to target 4.5.2 so I used the following which supposedly worked (the blog said)<br />
<br />
ilmerge /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2" /out:MERGED.First.dll First.dll Second.dll /keyfile:key.snk<br />
<br />
Note that if you strongly signed your First DLL don't assume the output will be strongly signed because it won't be. You have to add the /keyfile option to do that. <br />
<br />
Note also there are blogs that say don't try and point to C:\Windows... because that is not the correct location. You need to use the Reference Assemblies path given above.<br />
<br />
Well I didn't get the error and ILMerge started off and I waited. And waited. And waited. So basically ILMerge just hangs still consuming by the way 50% CPU just to fool you into thinking its actually doing something. <br />
<br />
Its the wrong syntax. The correct syntax uses /targetplatform not /lib<br />
<br />
ilmerge /targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2" /out:MERGED.First.dll First.dll Second.dll /keyfile:key.snkCharles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-48125918602878100092015-11-29T20:03:00.000+00:002015-11-29T20:03:05.218+00:00Creating a SharePoint OnLine Folder using CSOMSurprisingly I can't find a complete solution to this on the blogosphere. So let me put that right.<br />
<br />
First add two references to <br />
Microsoft.SharePoint.Client.dll<br />
Microsoft.SharePoint.Client.RunTime.dll<br />
<br />
I found them on my 64-bit server located here<br />
C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI<br />
<br />
In your code add a using statement<br />
<br />
<span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">using</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> Microsoft.SharePoint.Client;</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"></span><br />
<span style="font-family: inherit;">Then in your method add the following</span><br />
<span style="font-family: Consolas; font-size: x-small;"></span><br />
<span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">using</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> (</span></span><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;">ClientContext</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> ctx = </span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">new</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;">ClientContext</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">(site))</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">{</span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">var</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> securePassword = </span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">new</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> </span></span><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;">SecureString</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">();</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">
</span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">foreach</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> (</span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">char</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> c </span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">in</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> password)</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">{<br />
securePassword.AppendChar(c);<br />
}<br />
</span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">ctx.Credentials = </span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">new</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> Microsoft.SharePoint.Client.</span></span><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;"><span style="color: #2b91af; font-family: Consolas; font-size: x-small;">SharePointOnlineCredentials</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">(username, securePassword);</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">
</span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">var</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> list = ctx.Web.Lists.GetByTitle(doclib);</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">
</span></span><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;"><span style="color: blue; font-family: Consolas; font-size: x-small;">var</span></span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> folderRoot = list.RootFolder;</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">ctx.Load(folderRoot);<br />
ctx.ExecuteQuery();</span></span><span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;">folderRoot = folderRoot.Folders.Add(folder);<br />
ctx.ExecuteQuery();<br />
};</span> </span>Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-29105041013713406122015-08-31T11:36:00.000+01:002015-08-31T11:41:48.380+01:00Serialize a CRM Entity to XML in Sandbox mode PluginI have been struggling with this problem for a while. Previous posts have outlined the problem: how to get changes in CRM sent to Back Office systems as XML messages. When using CRM Online a big frustration is that you cannot serialize objects to XML because the WriteObject method of the serializer throws a security exception. <br />
<br />
While you can post the Context of a plugin to the Azure Service Bus, you have to use the CRM SDK to interpret this and turn it into something useful. My previous post outlines how to do this with an Azure Worker Process. <br />
<br />
(You could construct the XML message line by line using string builder but seriously who wants to do that?)<br />
<br />
I found a simple solution which may solve the problem. It was this <a href="https://code.msdn.microsoft.com/windowsdesktop/Simple-C-class-to-populate-a283c504#content" target="_blank">post</a> that provided the inspiration. It describes how to turn FetchXML results into a data table. Now FetchXML returns an entity collection and the code shows how to load that into a data table and it also handles the special CRM data types like Entity Reference. <br />
<br />
So there you are in a Sandbox plugin. You have the Post-Image entity and you want to convert that into a nicely structured XML file that you can post to the Azure Service Bus. You can use part of the code above (ignoring the FetchXML query) to convert the Post-Image to a data table. I put it into a function I called ConvertEntityToDataTable.<br />
<br />
Now getting XML is easy.<br />
<br />
DataSet ds = new DataSet("Invoice");<br />
DataTable dt = new DataTable("Attributes");<br />
ConvertEntityToDataTable(dt, entity);<br />
ds.Tables.Add(dt);<br />
<br />
string xml = ds.GetXml();<br />
<br />
The result looks like this (I've just given an extract)<br />
<span style="font-family: "Courier New", Courier, monospace;"><Invoice><br /> <Attributes><br /> <billto_city>London</billto_city><br /> <billto_line1>12 Hgh Street</billto_line1><br /> <billto_line2>Clapham Common</billto_line2><br /> <billto_line3>Clapham</billto_line3><br /> </Attributes><br /></Invoice></span><br />
<br />
Remember that PostImages provide their attributes in alphabetical order which is great for mapping structured XML messages. The Target entity does not so you would need to address that.<br />
The XML is missing some things I would need to add:<br />
(a) the xml declaration at the top specifying the encoding<br />
(b) a namespace to identify the message to an ESB<br />
<br />
But I am delighted with the result because now I can construct proper XML messages in a Sandbox plugin. <br />
<br />
The two functions required are shown below<br />
///////<br />
private void ConvertEntityToDataTable(DataTable dataTable, Entity entity)<br />
{<br />
DataRow row = dataTable.NewRow();<br />
foreach (var attribute in entity.Attributes)<br />
{<br />
if (!dataTable.Columns.Contains(attribute.Key))<br />
{<br />
dataTable.Columns.Add(attribute.Key);<br />
}<br />
row[attribute.Key] = getAttributeValue(attribute.Value).ToString();<br />
}<br />
foreach (var fv in entity.FormattedValues)<br />
{<br />
if (!dataTable.Columns.Contains(fv.Key + "name"))<br />
{<br />
dataTable.Columns.Add(fv.Key + "name");<br />
}<br />
row[fv.Key + "name"] = fv.Value;<br />
}<br />
dataTable.Rows.Add(row);<br />
}<br />
///////<br />
private object getAttributeValue(object entityValue)<br />
{<br />
object output = "";<br />
switch (entityValue.ToString())<br />
{<br />
case "Microsoft.Xrm.Sdk.EntityReference":<br />
output = ((EntityReference)entityValue).Name;<br />
break;<br />
case "Microsoft.Xrm.Sdk.OptionSetValue":<br />
output = ((OptionSetValue)entityValue).Value.ToString();<br />
break;<br />
case "Microsoft.Xrm.Sdk.Money":<br />
output = ((Money)entityValue).Value.ToString();<br />
break;<br />
case "Microsoft.Xrm.Sdk.AliasedValue":<br />
output = getAttributeValue(((Microsoft.Xrm.Sdk.AliasedValue)entityValue).Value);<br />
break;<br />
default:<br />
output = entityValue.ToString();<br />
break;<br />
}<br />
return output;<br />
}<br />
}Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com2tag:blogger.com,1999:blog-7178802206594541796.post-43330629578975199472015-08-16T16:11:00.000+01:002015-08-31T11:02:20.363+01:00Dynamics CRM 2015 Online and Azure Service Bus MessagesIf you've configured Dynamics CRM 2015 Online with Azure Service Bus you will know that the "message" it puts on the queue is the <strong>plugin execution context</strong>. This is the same context that you use within a plugin. You will know that to do anything with the context you have to use the Microsoft.Xrm.Sdk and extract the Pre or Post Image and the so called Target image. "Target" is s stupid name I always think. It contains the delta - the attributes that were changed during the operation. The Post Image of say an Update event will contain all the attributes that have values in it and excludes any attributes with null values. <br />
<br />
The reason for using the Azure Service Bus is usually to get data from CRM to your on-premise systems and more often than not you may be using an ESB to read messages from the Azure Service Bus. BizTalk for example has an adaptor that you just need to configure to read messages from Azure Service Bus. However any BizTalk developer is going to be very disappointed if you provide them with just a Plugin Execution Context because they will have to use the CRM SDK to convert it into an XML message. Even then the entity objects when serialized will result in a collection of KeyValuePairs. The biggest problem with that is trying to map it to a strongly typed schema particularly because the structure varies so much when attributes that are null are set to a value and vice versa. I've tried using the BizTalk mapper and failed. <br />
<br />
UPDATE: CRM Online restricts plugins to Sandbox mode and you cannot serialize objects to XML because this is prohibited. I have recently stumbled on a way of getting round this. This may provide a much simpler solution then described in the rest of this article. <br />
<br />
One solution is to have custom code that will read the context, convert it to a strongly typed schema and then put it back in another queue. This needs to be done serially to ensure that Ordered Delivery is maintained but at least it gets to a schema that is worthy of the name. <br />
<br />
Now you have to be careful when using CRM Online because if your plugins consume a lot of CPU they will be terminated with extreme prejudice. It is best to keep the code within your plugin as minimal as possible and then have the bulk of your code execute on an Azure VM where you don't need to worry about CPU usage because you can size the VM to suit. <br />
<br />
The best way to architect this is<br />
a) Have a Plugin that sends the Plugin Execution Context to a Azure Service Bus Queue<br />
b) Create an Azure Worker Process that reads messages from the Queue, creates an XML message and puts it into another Azure Service Bus Queue (be sure to maintain the order)<br />
c) If using BizTalk create a Receive Port that will read XML messages from the second Queue<br />
<br />
The Azure Worker Process is a lot like a Windows Service (in Azure its called a Cloud Service) and will automatically restart if it is stopped. When you deploy the Azure Worker Process it will create its own VM. You can supply configuration settings which in our case would include the EndPoint of the Queue we are reading from and the EndPoint of the Queue we are writing to.<br />
<br />
While you messages should be placed on the first queue using a plugin running synchronously, the Azure Worker Process is running asynchronously. If you want to post messages back to CRM because of a failure then you need to setup another asynchronous process to send the messages back to CRM. Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-52963266653828230992015-07-04T06:31:00.002+01:002015-08-31T10:56:08.586+01:00Dynamics CRM 2015 Online and Azure Service Bus In the previous <a href="http://charlesemes.blogspot.co.uk/2015/07/dynamics-crm-plugins-ordered-delivery.html" target="_blank">post</a> I talked about sending messages to another system via a message queue. This is the design pattern Microsoft recommends when you want to use Dynamics CRM Online to update systems that are on-premise. They recommend using Azure Service Bus and the integration is built into the Online version by creating a Service Endpoint. This is also available for the on-premise version.<br />
<br />
The plugin registration tool for Dynamics CRM offers the ability to register a Service EndPoint when you are connected to CRM Online. What is not clear though is that there are two ways you can configure it.<br />
First though there are two gotchas when setting up the Azure Service Bus.<br />
<br />
GOTCHA #1: You set up the Azure Service Bus Namespace using the Portal. Wrong. <br />
Doing it that way you no longer have the option to use ACS authentication and that is what the Plugin Registration tool uses. Delete it. Download the PowerShell Azure Commands add-in and run this command:<br />
New-AzureSBNamespace -Name <em>yourservice</em> -Location "<em>West Europe</em>" -CreateACSNamespace $true -NamespaceType Messaging<br />
<br />
The response you get returned is<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja5OVDGLOE7axodrCpeARSUn14n9lZ5pZtH5_tg-ZMHbUnFKt1EJFdHvibA28WwUIE9372en5zHZ-zAGwCUfPpwjIiRObsD9-34KHjS3wIvPkZG7tpPfKytfl07ZLlXGwfRD7Bw4Y0iK8/s1600/PowerShellNewAzureVM+repsonse.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja5OVDGLOE7axodrCpeARSUn14n9lZ5pZtH5_tg-ZMHbUnFKt1EJFdHvibA28WwUIE9372en5zHZ-zAGwCUfPpwjIiRObsD9-34KHjS3wIvPkZG7tpPfKytfl07ZLlXGwfRD7Bw4Y0iK8/s640/PowerShellNewAzureVM+repsonse.png" width="640" /></a></div>
<br />
You need to use the DefaultKey when the Plugin Registration tool prompts you for the Management Key!<br />
<br />
GOTCHA #2: You create the Queue (or whatever) using the Portal or PowerShell. Wrong.<br />
You need to leave this for the Plugin Registration tool to do.<br />
<br />
I won't give the rest of the details for configuring the endpoint because that is covered in other blogs.<br />
<br />
Once you have the Service EndPoint registered there are two ways forward.<br />
<br />
The first and seemingly the most attractive option is you can register steps and images right there under the endpoint just as you would do with a plugin. The advantage is that this is a zero code solution. Just by configuring an Entity with the appropriate step and image you can get messages in your queue (or whatever). The thing is though is this method only supports Asynchronous operations. That may be fine if you have a very simple CRM solution and want to configure only one or two entities. In more real world scenarios this is not going to work for you because it won't guarantee ordered delivery. That is what I covered in my previous <a href="http://charlesemes.blogspot.co.uk/2015/07/dynamics-crm-plugins-ordered-delivery.html" target="_blank">post</a>. To maintain Ordered Delivery you must use synchronous plugins steps.<br />
<br />
The second route is to create an Azure-aware plugin. There is sample code in the SDK for doing this and out there in blogosphere. In this case you just create the service endpoint and copy the Id that it creates. Create your Azure-aware plugin and paste the Id into the Unsecure Configuration section. Register your plugin steps and images as usual. The plugin uses an instance of the IServiceEndpointNotificationService and essentially posts the context (using the Execute method) to the Service Bus endpoint. The point here though is that you have full choice over how to register your steps, so if you need Ordered Delivery you can choose Synchronous. <br />
<br />
Personally I find the whole method of configuring a Service EndPoint sucks. What about when I want to deploy this to other environments? I am going to have to repeat the manual steps for each environment and when I deploy my Azure aware plugin I am going to have to amend the Id each time. Now you might argue this will be a one off process and its no big deal. But I prefer my deployments not to involve manual steps so I'm inclined to post messages to the Azure Service Bus using code and have the connection string stored in a configuration entity along with other environment settings. Remember though that you have to use the REST API to post messages because the plugin runs in Sandbox mode. Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-54159497588278646352014-06-25T20:56:00.001+01:002015-08-16T16:34:03.107+01:00Activation error occurred while trying to get instance of type LogWriter, key ""<span style="font-family: Arial, Helvetica, sans-serif;">I have blogged about this error before and this post has become one of my most viewed. I hope it provides the answer you need and it makes sense. Please feel free to leave a comment!</span><br />
<br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><em>Microsoft.Practices.ServiceLocation.ActivationException : Activation error occurred while trying to get instance of type LogWriter, key ""<br /> ----> Microsoft.Practices.Unity.ResolutionFailedException : Resolution of the dependency failed, type = "Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter", name = "(none)".<br />Exception occurred while: while resolving.<br />Exception is: InvalidOperationException - The type LogWriter cannot be constructed. You must configure the container to supply this value.</em></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><em></em></span><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-family: Arial, Helvetica, sans-serif;"> It occurs when using Microsoft.Practices.EnterpriseLibrary for logging errors. There are lots of blogs that reference this error and they mostly say the error is caused by:</span><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">a) an error in your configuration (often the database connection string)</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">b) not all the DLLs are present</span><br />
<br />
That was not my situation. I was logging just to the event log and I was certain I had all the DLLs in the bin directory of my web service. The error occurred when I deployed the web service to a new environment. <br />
<br />
I spent many hours tracking down the cause. In this case it was because Microsoft.Practices.EnterpriseLibrary was installed on the target environment and the DLLs were registered in the GAC. <br />
<br />
Now as you know, .NET will look for the location of DLLs in a specific order and the GAC is at the top of the list. The problem is, when the Enterprise Library DLLs are installed in the GAC then it is unable to determine the location of the configuration file. I guess that when they are just present in the bin directory the location of the configuration file is presumed to be "up a level". Removing the DLLs from the GAC was not an option, I needed to find a way that would work with the DLLs in the bin directory or in the GAC. <br />
<br />
I have a DLL that I use to simplify the calls when logging an error. It has several constructors to create log entries of different severities. Below is the code that includes just the critical error constructor. <br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">using Microsoft.Practices.EnterpriseLibrary.Logging;</span><br />
<span style="font-family: "Courier New", Courier, monospace;"></span><br />
<span style="font-family: "Courier New", Courier, monospace;">namespace Ciber.Common.Logging<br />{</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> public static class Logging<br /> {</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> public static void LogCritical(string message, string title, string category)<br /> {<br /> Logger.Write(message, category, 3, 1, TraceEventType.Critical, title);<br /> }</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> }</span><br />
<span style="font-family: "Courier New", Courier, monospace;">}</span><br />
<br />
Now I have many places in my code where I reference the LogCritical method and I didn't want to change them. What I needed was a way to link up to the loggingConfiguration section in my web.config.<br />
<br />
Firstly I added two additional references and using statements<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;<br />using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;</span><br />
<br />Then I added this method to my class:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">public static LogWriter CreateLogger()<br />{<br /> EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(ReadConfigSource());<br /> var logWriter = EnterpriseLibraryContainer.Current.GetInstance<logwriter>();<br /> return logWriter;<br />}</logwriter></span><br />
<br />
What that allows is to create a default container from an XML location that I specify and which in my case contains the loggingConfiguration section. <br />
<br />
I can then get an instance of the LogWriter class by calling EnterpriseLibraryContainer.Current.GetInstance<logwriter>(). </logwriter><br />
<br />
Before I list the ReadConfigSource method let me first show the modified constructor from above which now reads:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">public static void LogCritical(string message, string title, string category)<br />{<br /> LogWriter logger = CreateLogger();<br /> logger.Write(message, category, 3, 1, TraceEventType.Critical, title);<br />}</span></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Note the lower case L on the logger object. So great, my calls that write to the event log don't need to be changed and I have the ability to specify where my loggingConfiguration section is located. </span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;">Below is the code for the ReadConfigSource() method. Two very important points here. </span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;">1) I use OpenWebConfiguration() with HttpRuntime.AppDomainAppVirtualPath which will resolve correctly both in debug mode and in deployed mode. Don't be tempted to use OpenWebConfiguration(null) or OpenWebConfiguration("/") which will work fine in Debug mode but will fail when deployed. </span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;">2) I added this to the start of my loggingConfiguration string @"<?xml version=""1.0"" encoding=""utf-8"" ?>". Without it the loggingSection.ReadXml(xmlReader); line will fail. </span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: "Courier New", Courier, monospace;">public static IConfigurationSource ReadConfigSource()<br />{<br /> var configSource = new DictionaryConfigurationSource();<br /> string virpath = HttpRuntime.AppDomainAppVirtualPath;<br /> Configuration configFile = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(virpath);</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> ConfigurationSection section = configFile.GetSection("loggingConfiguration");</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> if (section != null)<br /> {<br /> string loggingConfig = @"<?xml version=""1.0"" encoding=""utf-8"" ?>";<br /> loggingConfig = loggingConfig + section.SectionInformation.GetRawXml();</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> LoggingSettings loggingSection = null;<br /> using (var stringReader = new StringReader(loggingConfig))<br /> {<br /> var xmlReader = XmlReader.Create(stringReader,<br /> new XmlReaderSettings() { IgnoreWhitespace = true });</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> loggingSection = new LoggingSettings();<br /> loggingSection.ReadXml(xmlReader);<br /> xmlReader.Close();<br /> }</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> configSource.Add(LoggingSettings.SectionName, loggingSection);<br /> }</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> return configSource;</span><br />
<span style="font-family: "Courier New", Courier, monospace;">}</span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;">I am pleased with the result. Hope it works for you.</span>Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-56863516245562794772015-07-04T05:55:00.002+01:002015-08-16T15:48:12.174+01:00Dynamics CRM, Plugins, Ordered Delivery and QueuesThis post applies to both Dynamics CRM Online and On-Premise. The scenario is where you need to keep another system synchronized with changes to Dynamics CRM entities. To make this loosely coupled you can write messages to a queue. If your target system is unavailable, the queue can store messages until it comes back online. The same design pattern is recommended for Dynamics CRM Online where messages are written to Azure Service Bus queue. You then have a process on-premise (it my be an ESB) that reads messages from the queue and sends then on to the target system. <br />
<br />
This post stems from work I did on a previous project where we used CRM on-premise to write messages to MSMQ. If you are reading this far I assume you already know about Ordered Delivery but here is the bottom line:<br />
<br />
If you want to maintain Ordered Delivery you must use Synchronous Plugins.<br />
<br />
If you use a plugin registered for asynchronous it may appear to give you Ordered Delivery 4 out of 5 times, but you cannot guarantee it for all messages.<br />
<br />
You can spend the time proving it for yourself or read this explanation. <br />
<br />
We had a custom entity for address that meant you could create an address that was the primary address or the regulatory address or both. The business rule was that you could only have one <strong>active</strong> address for primary and regulatory. To achieve this we created a plugin on that fires on Create of an address and as a Pre-Operation, if you set the both primary and regulatory flags on the address to true it checks if any existing addresses are primary or regulatory, sets them to false and then deactivates the address(es). Now the target system has to obey the same logic so we need to send any messages to it n the correct order, i.e. in ordered delivery.<br />
So I created a plugin that was generic and would write a message out to MSMQ. I registered it to run as a Post Operation on Create and Update of an Address and set it to run Asynchronously. <br />
In one test case we have two existing addresses one set as primary, the other set as regulatory (lets call them 'Primary' and 'Regulatory'), We create a new address ('New') and set it to both primary and regulatory. That creates 5 messages. <br />
1. Update of Primary to set the primary flag to false<br />
2. Update of Primary when status is set to deactivate<br />
3. Update of Regulatory to set the regulatory flag to false<br />
4. Update of Regulatory when status is set to deactivate<br />
5. Create of the New address<br />
<br />
Now you want to maintain the order that the addresses were written to the database. The Create must come last or you've broken the business rule about only have one active primary or regulatory address. With the on-premise CRM I could examine the Asynchronous table and could see the 5 messages there. They were flagged as belonging to the same transaction but when you looked at the processed time they were all identical. All five records are executed simultaneously and its a matter of chance which message gets in the queue first. There is an order, but its not consistent. <br />
<br />
BizTalk works in a similar way to the CRM Asynchronous Service and its architected that way for performance reasons. <br />
<br />
When I changed the plugin to work synchronously then it does maintain the correct order of the messages. You do need to pay attention though to the Rank when you have multiple plugins registered on the same entity for the <strong>same</strong> <strong>stage.</strong> By default, Rank is zero but you can put any integer up to 99 into it, and this will set the order that the plugins fire in. I wanted my message to be the last plugin to execute so I set it to 99. Remember though that it affects the order <br />
of the plugins within the same stage. The plugin pipeline always executes as <br />
1. Pre-Validation<br />
2. Pre-Operation (before the database write)<br />
3. Post-Operation(after the database write)<br />
<br />
Here is the bottom line again<br />
<br />
If you want to maintain Ordered Delivery you must use Synchronous Plugins.<br />
Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-7427407929495200012015-03-05T16:54:00.002+00:002015-03-05T16:54:38.417+00:00Calling a WCF Web Service over HTTPS (SSL)I was recently trying to access a web service that I wanted to secure over HTTPS. I got it working as an HTTP service, as you do, and made sure that I had a certificate on the server and enabled the https protocol. <br />
I was using basic Http binding and here are the changes that need to be made<br />
<br />
<security mode="Transport"><br /> <transport clientCredentialType="None" /> <br />
<br />
That now worked in the browser if I prefixed the url with https://<br />
<br />
Next step was that I needed to call the web service where I was not able to access a web.config or an app.config. Without the service reference being available you have to do this in code. First thing is to make sure you have a copy of the interface class accessible in the client. It doesn't need to be the same name but it does need to specify the operation contract exactly.<br />
<br />
[ServiceContract]<br /> public interface IFormDefinition<br /> {<br />
[OperationContract]<br /> [FaultContract(typeof(CRMSoapFault))]<br /> void PublishFormMetaData(string crmEndPoint, string formId, string webResource, string token);<br /> }<br />
[DataContract]<br /> public class CRMSoapFault<br /> {<br /> public CRMSoapFault(string errorMsg)<br /> {<br /> this.ErrorMsg = errorMsg;<br /> }<br /> /// <summary><br /> /// This property is used to pass the custom error information <br /> /// from service to client.<br /> /// </summary><br /> [DataMember]<br /> public string ErrorMsg { get; set; }<br />
}<br />
<br />
To call the web service and set the binding information through code to match this you need to add:<br />
<br />
BasicHttpBinding myBinding = new BasicHttpBinding();<br /> myBinding.Security.Mode = BasicHttpSecurityMode.Transport;<br /> myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;<br /> EndpointAddress myEndpoint = new EndpointAddress(endPointUrl);<br /> ChannelFactory<iformdefinition> myChannelFactory = new ChannelFactory<iformdefinition>(myBinding, myEndpoint);</iformdefinition></iformdefinition><br />
try<br /> {<br /> IFormDefinition wcfClient1 = myChannelFactory.CreateChannel();<br />
// call the web service method<br /> wcfClient1.PublishFormMetaData(crmEndPoint, formId, webResource, token);<br />
<br /> }<br /> catch(FaultException<crmsoapfault> faultEx)<br /> {</crmsoapfault><br />
}Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-12596692430806591582015-03-02T18:19:00.000+00:002015-03-02T18:19:24.371+00:00Accessing SharePoint Online with Web ClientMisleading title really because if you try and access SharePoint Online using the WebClient it will fail to authenticate. What you need to do is use the CookieContainer and SharePointOnlineCredentials. <br />
I got the basics of this from this <a href="http://stackoverflow.com/questions/18836306/upload-document-to-sharepoint-2013-online-using-webservices" target="_blank">post.</a> and also from this <a href="http://tomaszrabinski.pl/wordpress/2013/03/18/connecting-to-office-365-using-client-side-object-model-and-web-services/" target="_blank">post</a> which uses a class inherits from WebClient. It mentions that you need the SharePoint Client Components SDK which will install Microsoft.SharePoint.Client.DLL and Microsoft.SharePoint.Client.RunTime.DLL. Add references to both DLLs in your project and add these two using statements<br />
<br />
<span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">using</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> Microsoft.SharePoint.Client;</span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-size: small;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">using</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> System.Security;</span></span></span><br />
<span style="font-size: small;"></span><br />
<br />
</span><span style="font-family: Consolas; font-size: x-small;"><span style="font-size: small;">Add this class to your project</span><br />
<span style="font-size: small;"> </span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">public</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">class</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">ClaimsWebClient</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> : </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">WebClient</span></span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas; font-size: small;">{</span><span style="font-size: small;"> </span></span><span style="font-size: small;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">private</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">CookieContainer</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> cookieContainer;</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas; font-size: small;">
</span></span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">public</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> ClaimsWebClient(</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">Uri</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> host, </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">string</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> userName, </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">string</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> password)</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"><span style="font-size: small;"> </span><br />
<span style="font-size: small;">{</span><br />
<span style="font-size: small;">
</span><br />
<span style="font-size: small;"> cookieContainer = GetAuthCookies(host, userName, password);</span><br />
<span style="font-size: small;">
</span><br />
<span style="font-size: small;"> }</span><br />
<span style="font-size: small;">
</span></span><span style="font-size: small;"> </span></span><span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">protected</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">override</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">WebRequest</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> GetWebRequest(</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">Uri</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> address)</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"><span style="font-size: small;">{</span><br />
<span style="font-size: small;">
</span></span></span><span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">WebRequest</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> request = </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">base</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">.GetWebRequest(address);</span></span></span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;">
</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> if</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> (request </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">is</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">HttpWebRequest</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">)</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-size: small;"> </span><br />
<span style="font-family: Consolas; font-size: small;"> {</span><span style="font-size: small;"> </span></span><span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> (request </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">as</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">HttpWebRequest</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">).CookieContainer = cookieContainer;</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"><span style="font-size: small;"> }</span><br />
<span style="font-size: small;"> </span></span></span><span style="font-size: small;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> return</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> request;</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"><span style="font-size: small;"> </span><br />
<span style="font-size: small;"> }</span><br />
<span style="font-size: small;">
</span></span><span style="font-size: small;"> </span></span><span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">private</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">static</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">CookieContainer</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> GetAuthCookies(</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">Uri</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> webUri, </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">string</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> userName, </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">string</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> password)</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas; font-size: small;">{</span></span><span style="font-size: small;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> var</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> securePassword = </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SecureString</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">();</span></span></span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> foreach</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> (</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">var</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> c </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">in</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> password) { securePassword.AppendChar(c); }</span></span></span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> v</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">ar</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> credentials = </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SharePointOnlineCredentials</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">(userName, securePassword);</span></span></span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;">
</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">var</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> authCookie = credentials.GetAuthenticationCookie(webUri);</span></span></span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> var</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> cookieContainer = </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">CookieContainer</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">();</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas; font-size: small;"> cookieContainer.SetCookies(webUri, authCookie);</span><span style="font-size: small;"> </span></span><span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> return</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> cookieContainer;</span></span></span><br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"><span style="font-size: small;">}</span><br />
<span style="font-size: small;">
</span><br />
<span style="font-size: small;"> }</span></span> </span><br />
<span style="font-size: small;"></span><br />
<span style="font-size: small;">Then call the ClaimWebClient class in the same way as you would the WebClient. Note that you do not need to set the credentials because it is done within the ClaimWebClient class.</span><br />
<br />
<span style="font-family: Consolas; font-size: x-small;"><span style="font-family: Consolas; font-size: x-small;"> </span></span><span style="font-size: small;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">ClaimsWebClient</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> wc = </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">ClaimsWebClient</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">(</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">Uri</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">(sharePointSiteUrl), userName, password);</span></span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas; font-size: small;">
</span></span><br />
<span style="font-size: small;"><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">byte</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">[] response = wc.DownloadData(sourceUrl);</span></span></span><br />
</span>Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com2tag:blogger.com,1999:blog-7178802206594541796.post-59724285837158951682015-02-28T15:32:00.004+00:002015-02-28T15:32:30.105+00:00Raising SoapFaults on a Web Service<span style="font-family: Verdana, sans-serif;">I have used SoapFaults (FaultExceptions) on Web Services before so here is quick recap. In your Interface class add this declaration</span><br />
<br />
<span style="color: #2b91af; font-family: Consolas;">[DataContract]</span><br />
public class SPSoapFault
<br />
{
<br />
public<span style="font-family: Consolas;"> </span>SPSoapFault(string errorMsg)
<br />
{
<br />
this.ErrorMsg = errorMsg;
<br />
}
<br />
[<span style="color: #2b91af; font-family: Consolas;">DataMember</span>]
<br />
public string ErrorMsg { get; set; }<br />
}
<br />
<br />
<span style="font-family: Verdana, sans-serif;">Beneath the OperationContract declaration of the method you want to use this on addthe FaultContract attribute</span><br />
<br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"> [</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">OperationContract</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">]</span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"> [</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">FaultContract</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">(</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">typeof</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">(</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SPSoapFault</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">))]</span></span><br />
<br />
<span style="font-family: Verdana, sans-serif;">Now in the service you can throw FaultExceptions of this type</span><br />
<br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">throw</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">FaultException</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"><</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SPSoapFault</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">>(</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SPSoapFault</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">(</span></span><span style="color: #a31515; font-family: Consolas;"><span style="color: #a31515; font-family: Consolas;"><span style="color: #a31515; font-family: Consolas;">"The byte array is null"</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">), </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">FaultReason</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">(</span></span><span style="color: #a31515; font-family: Consolas;"><span style="color: #a31515; font-family: Consolas;"><span style="color: #a31515; font-family: Consolas;">"Required parameter"</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">));</span></span><br />
<span style="font-family: Consolas;"></span><br />
<span style="font-family: Verdana, sans-serif;">Note that you must add a Fault Reason.</span><br />
<span style="font-family: Verdana, sans-serif;"></span><br />
<span style="font-family: Verdana, sans-serif;">When calling this from a client application make sure you declare the faultexception that is in the web service references</span><span style="font-family: Consolas;"><span style="font-family: Verdana, sans-serif;">.</span> </span><br />
<span style="font-family: Consolas;"></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"><span style="font-family: Consolas;">SPService.</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SPSoapFault</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> spfault = </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">new</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> SPService.</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SPSoapFault</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;">();</span></span></span><br />
<br />
<span style="font-family: Verdana, sans-serif;">the catch block of your try catch should include this</span><br />
<span style="font-family: Consolas;"></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">catch</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> (</span></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">FaultException<</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"><spservice .="" font=""></spservice></span><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;"><span style="color: #2b91af; font-family: Consolas;">SPSoapFault></span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> faultEx)</span></span></span><span style="font-family: Consolas;"><br />
<span style="font-family: Consolas;">
{<br />
<br />
spfault = faultEx.Detail;<br />
</span> </span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">string</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> error = spfault.ErrorMsg;</span></span><br />
<span style="font-family: Consolas;"><span style="font-family: Consolas;"> </span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">string</span></span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"> reason = faultEx.Reason.ToString();</span></span><span style="font-family: Consolas;"><span style="font-family: Consolas;"><br />
}</span></span>Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-70075733674125408172014-11-04T14:03:00.001+00:002014-11-04T14:03:47.320+00:00Dynamics CRM 2013 Microsoft Web Page Dialog errorIf you use Dynamics CRM 2013 for any length of time then you will have noticed the Microsoft dialog box that pops up intermittently. It seems to occur randomly and is hard to reproduce. As far as I can see it doesn't result in any data loss so I just ignore it.<br />
<br />
But the screen is irritating and doesn't give a good impression to first time users. <br />
<br />
It can be disabled by logging on to CRM as the System Administrator and going to Administration and Privacy Preferences. On the Privacy Preferences dialog click the Error Reporting tab. Select "Specify the Web application error notification preferences on behalf of users" checkbox and then select the radio button "Never send an error report to Microsoft". <br />
<br />
The errors are still happening but at least the screen isn't popping up. Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-52301915569892112962014-07-26T13:48:00.002+01:002014-07-26T13:48:16.292+01:00Unit Testing Dynamics CRM PluginsNow there are lots of approaches to unit testing Dynamics CRM plugins and some frameworks for creating <a href="https://community.dynamics.com/crm/b/zhongchenzhoustipstricksandportaldevelopment/archive/2012/11/26/dynamics-crm-2011-unit-test-part-14-rhino-mocks-with-crm-plugin.aspx" target="_blank">Mocks</a>. <br />
<br />
Recently an XRM Test Framework has been made <a href="http://waelhamze.com/category/xrm-test-framework/" target="_blank">available</a>. <br />
<br />
But I like the simple approach(es) outlined in this <a href="http://happycrm.blogspot.co.uk/2012/02/unit-testing-crm-2011-plugins.html" target="_blank">blog</a>. It doesn't use any tools because you write the code yourself which can be an advantage or a drawback. If you don't have time to evaluate a tool and think you can build unit tests quickly, then this is probably a good approach. <br />
<br />
The first approach described in this blog may involve refactoring your code but it is the best approach if you want to run unit tests during an automated build process. It involves moving most of the code out of the Execute method of the Plug-in and putting it into a "logic" Class Library. So the unit tests simply call the Class library and you avoid having to go through the executing the plug-in. OK, it may not test that the attribute filter you included is working properly but at least it tests your code prior to deployment and so would catch any errors. These approaches, are not mutually exclusive, you would combine them to ensure the quality of the code. <br />
<br />
Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-10779793493398145772014-07-11T19:35:00.002+01:002014-07-26T13:23:32.037+01:00Automated Builds and Incrementing Version NumbersIncrementing the version number when you do a build in Visual Studio seems an obvious requirement.<br />
<br />
I found this great <a href="http://vagif.bloggingabout.net/2010/04/24/using-t4-templates-to-manage-assembly-version-information/" target="_blank">post</a> on using a T4 template. I followed the instructions carefully by creating a common DLL library project, removing the Class1.cs and adding a AssemblyVersion.tt file using the code that was provided. <br />
<br />
As the author points out you just need to save the T4 template file and it will create a .cs file with the assembly information in it with the appropriate build number. In my case it created a AssemblyVersion.cs file.<br />
<br />
As advised, I removed the AssemblyVersion and AssemblyFileVersion attributes from AssemblyInfo.cs files of all the projects that I wanted to apply this version number to. <br />
<br />
I then added the AssemblyVersion.cs file to the projects as a link but I moved the file under the Properties folder so it appears directly under AssemblyInfo.cs. If you've not added a link before, select Add existing.. and select the file and you will see the Add button in the dialog has a little down arrow which will reveal the "Add as a link" option. <br />
<br />
Sure enough when I built the solution, my DLLs had the correct version number. <br />
<br />
But I realised I had to manually save the T4 file each time to refresh the version.cs file. Now I want to have automated builds so I was looking for a way to process the T4 template before each build.<br />
<br />
I finally found the answer from this blog <a href="http://msdn.microsoft.com/en-us/library/bb126245.aspx" target="_blank">entry</a>. There is a TextTransform.exe file that will take the T4 template and produce the cs file. <br />
<br />
TextTransform.exe is located here<br />
<strong>\Program Files\Common Files\Microsoft Shared\TextTemplating\11.0</strong> <br />
<br />
or <br />
<br />
<strong>\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\11.0</strong> <br />
<br />
In the Pre-Build event of the version project I added this<br />
"C:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\11.0\TextTransform.exe" ($ProjectDir)AssemblyVersion.tt -out ($ProjectDir)AssemblyVersion.cs<br />
<br />
When I build the solution the version number is incremented. Brilliant. <br />
<br />
You can of course use lots of different variations for incrementing the build or revision number. But remember the 4 parts are<br />
<br />
major.minor.build.revision<br />
<br />
I changed the original template to modify the AssemblyFileVersion only and not the AssemblyVersion. I am still able to distinguish between the DLLs from different builds but the all important AssemblyVersion I control. The first deployment will be version 1.0.0.0, I can then branch the code and change the T4 template to the next release 1.1.0.0.<br />
<br />
To increment from the previous revision number using a T4 template there is a good blog post <a href="http://www.codeproject.com/Tips/656583/Walkthrough-How-to-increment-AssemblyFileVersion" target="_blank">here</a>. If you want to change both build and revision number use methods which use the declaration starting with <#+<br />
using System.Reflection;<br />
[assembly: AssemblyCompany("C Hoare & Co")]<br />
[assembly: AssemblyVersion("1.0.0.0")]<br />
[assembly: AssemblyFileVersion("1.0.<#= BuildNumber() #>.<#= RevisionNumber() #>")]<br />
<#+<br />
private int BuildNumber()<br />
{<br />
int buildNumber = (int)(DateTime.UtcNow - new DateTime(2014,7,1)).TotalDays;<br />
return buildNumber;<br />
}<br />
#><br />
<#+<br />
private int RevisionNumber()<br />
{<br />
int revisionNumber = 0 ; <br />
// other code to increment revision number<br />
return revisionNumber;<br />
}<br />
#><br />
<br />
A couple of further points. <br />
1. Make sure there is no white space after the final #> or you will get an error.<br />
2. If using TFS then add to the pre-build event, get latest version of AssemblyVersion,cs, check out before the TextTransform. In the Post Build event check the cs file back in. <br />
3. To pause incrementing the build number, just unload the project from the solution.<br />
4. SharePoint 2010 only recognises the major and minor number of the AssemblyVersion. That's why controlling the AssemblyVersion is important, but you can increment the AssemblyFileVersion instead.<br />
<br />
<strong>UPDATE</strong><br />
When I started using this method for automatic builds, I realised that using Pre and Post Build events to process the T4 template produced some errors. I moved the commands into a PowerShell script and I execute this as a scheduled task an hour before my scheduled builds run. I still have the version project but it becomes simple container for the T4 template and the CS file, I don't need to add it to any solutions. I still like this approach. I have one place where I control Assembly and Assembly File Versions.Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-72633458779218784052014-07-23T20:56:00.001+01:002014-07-23T20:56:19.034+01:00VS 2012 and TFS 2013 Build Process Templates - How to add DefaultTemplate.11.1.xamlToday was one of those days that forced me to blog. It was a deeply frustrating day but ended on a high and I thought to myself why hasn't anyone blogged that before?<br />
<br />
I have a VS 2012 solution that was held in TFS 2012 and I've now moved it to TFS 2013. I did not want to upgrade the development team to VS 2013 just at this moment. Besides, I thought VS 2012 and TFS 2013 were compatible, right? I was trying to set up automated builds so I created a Build Controller on my build server using the TFS 2013 DVD image. <br />
<br />
I opened my solution and selected create Build Definition and selected the Default Template (TfvcTemplate.12.xaml). I immediately saw lots of errors and a few minutes Googling revealed that you can't use this TFS 2013 template for VS 2012 projects. <br />
<br />
Now the link just below the drop down list of build process templates should direct you to where the templates are stored in Source Code Explorer. Now my link showed #/1/BuildProcessTemplates/TfvcTemplate.12.xaml and that navigated to nowhere. I mean the link doesn't even start with $ so how was that ever going to work?<br />
<br />
So I started trying to find the XAML files for the Build Process Template that the Build Controller was using. If they weren't in TFS then presumably they were on the hard drive. No. Then how do I add a Build Process template to the list? Hours of searching revealed nothing and this was the deeply frustrating part of the day.<br />
<br />
Then I found this <a href="http://blogs.msdn.com/b/jpricket/archive/2010/04/08/tfs-2010-managing-build-process-templates-what-are-those.aspx" target="_blank">blog</a>. The author very kindly provides the source code to create a Console application that will allow you to list <span style="font-family: inherit;">the</span> Build Process Templates you have and crucially to add a new one. BTW, the two references that you need to add for this to work can be found in the GAC (C:\Windows\assembly\GAC_MSIL)<br />
<br />
Now I <span style="font-family: inherit;">already had the DefaultTemplate.11.1.xaml file that I needed for my VS 2012 solution because it was sitting there in the BuildProcessTemplates directory beneath the root of my project in TFS. </span><br />
<br />
I used the command line similar to this:<br />
<br />
ManageBuildTemplates.exe <a href="http://jpricket-test:8080/tfs/TestCollection0">http://jpricket-test:8080/tfs/TestCollection0</a> TestProject add $/TestProject/BuildProcessTemplates/MyTemplate.xaml<br />
<br />
to add my Build Process Template. As soon as I selected a new Build Definition I could see my newly added template and I was cooking. A few minutes later I had my first successful automated build. From the depths of despair to deep joy in just a few minutes. <br />
<br />
Which of course made me think - why hasn't anybody blogged this before? And Microsoft what the hell were you thinking? Why isn't this essential tool included with TFS? Thanks again Jason Prickett for providing the source.<br />
<br />
Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com2tag:blogger.com,1999:blog-7178802206594541796.post-86060812424063659552014-03-10T15:21:00.001+00:002014-07-16T16:13:10.319+01:00Unit Tests and Microsoft Practices Logging<span style="font-family: Arial, Helvetica, sans-serif;">I created a WCF Web Service where I am logging errors using the Microsoft.Practices.EnterpriseLibrary tools for handling exceptions and logging.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">When I called the web service using the WCF Test Client, all was well and I recorded the errors successfully.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">But when I added some unit tests that would also generate an exception when calling the web service, I received the following error:</span><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><em>Microsoft.Practices.ServiceLocation.ActivationException : Activation error occured while trying to get instance of type LogWriter, key ""<br /> ----> Microsoft.Practices.Unity.ResolutionFailedException : Resolution of the dependency failed, type = "Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter", name = "(none)".<br />Exception occurred while: while resolving.<br />Exception is: InvalidOperationException - The type LogWriter cannot be constructed. You must configure the container to supply this value.</em></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">I spent some time Googling and finally found this </span><a href="http://lifewithdotnet.blogspot.co.uk/2011/07/when-enterprise-library-meets-unit-test.html" target="_blank"><span style="font-family: Arial, Helvetica, sans-serif;">post</span></a><span style="font-family: Arial, Helvetica, sans-serif;"> which explains all.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">You need to copy the relevant sections of the web.config that refer to Enterprise Library into the app.config of the Unit Test Project. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">This also applies if you have an AppSettings entry (e.g. a Dynamics CRM Connection string) as this also needs to be copied into the app.config.</span><br />
<br />
<br />
<br />
<br />
<span style="font-style: italic;"><br /><br />
<strong></strong> </span>Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com1tag:blogger.com,1999:blog-7178802206594541796.post-59391506670063918082014-05-28T19:28:00.000+01:002014-05-28T20:00:46.009+01:00BizTalk Rules Engine - Lessons LearnedIf you are looking for a few hours to while away then the BizTalk Rules Engine will certainly occupy the time. Hopefully this post might give you some hours back. This post is about using the BizTalk Rules Engine within an orchestration. In my case I want to set Boolean values that can then be used in decision shapes within the orchestration. The sort of thing would be "if IsCreateCase is true then do this, else do that". A quick summary of the things I learnt is:<br />
<ol>
<li>Write the results of the BRE rule back into the message</li>
<li>Keep your rules really simple</li>
<li>Find a workaround for null nodes</li>
<li>Put the Call Rules shape in a scope and add an exception handler</li>
</ol>
The easiest thing is to write the BRE rule results back into the message. When you set up the Call Rules shape it asks for only two things, the name of the BRE policy and the input parameters. <br />
In my case the input is an XML message and if you create an Action to write back to a node in the message, it will actually clone the message. <br />
<br />
For me it was a benefit to have these results within the message as it provided a means of checking the logic was correct. I created some xs:boolean elements in my message and set the default value to false. That is key because the target element must exist within the message. Now all I had to think about was writing the conditions that will evaluate to true.<br />
<br />
During testing of the policy in the Business Rules Composer I soon realised that it is best to keep the rules really simple if you can. That is because when testing it displays the name of the rule that was fired so it is easier to check if these are simple rules. <br />
<br />
My next problem was around the message instances. I am comparing the value of two nodes (both called CreateCase) in the message but in some valid message instances one of the nodes can be completely absent.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP5i3We-FoxsvqpT5jfG6pM0Fi-d_TH4oK5wiGucwqvK2xquCZBwB8hIKvHdieaCDa7IGwvQX1xGpyuth30YbQ6OY4gCXDzLFOCFkvfNH-NiOlua0dCgbvhmSWkC_XJrPts1lyww0XwAw/s1600/Message.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP5i3We-FoxsvqpT5jfG6pM0Fi-d_TH4oK5wiGucwqvK2xquCZBwB8hIKvHdieaCDa7IGwvQX1xGpyuth30YbQ6OY4gCXDzLFOCFkvfNH-NiOlua0dCgbvhmSWkC_XJrPts1lyww0XwAw/s1600/Message.jpg" height="168" width="640" /></a></div>
<br />
In code you would of course check for the existence of the Before/CreateCase node before checking its value because otherwise you would get en exception with the first example message. I thought that BRE would do this if I used a condition which checked for its existence, but I just could not get that to work. No combination of logical AND and OR would do the trick. <br />
<br />
In frustration I gave up and used the map which transforms the external schema to my internal one to add the necessary elements as nulls. I blogged about creating a null node <a href="http://charlesemes.blogspot.co.uk/2011/11/how-to-create-null-destination-node-in.html" target="_blank">here</a>. I used the logical existence operator ? with the logical not ! along with the Value Mapping functoid. Having a null element for CreateCase made all the difference and simplified my rules even more. <br />
<br />
Having tested my rules thoroughly in the Business Rules Composer I published and deployed it to BizTalk. In the orchestration I added the Call Rules shape within a scope and created an Exception Handler that trapped errors of type PolicyExecutionException (you need to add a reference to Microsoft.Rule.Engine.DLL).<br />
<br />
In the end I am very pleased with the result. One simple shape determines the logic that my message will follow through the orchestration. If I have to amend the rules I can do so without redeploying the orchestration. Sweet. Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-10573393853447885192014-04-28T14:00:00.001+01:002014-04-28T14:00:23.482+01:00BizTalk Deployment Framework 5.5 ErrorsI was working with the BizTalk Deployment Framework version 5.5 and I kept hitting an error when deploying. The error arose with the xml pre-processor step as it tries to create the port bindings file form the master and the environment settings file. The error was<br />
<br />
InitSettingsFilePath:<br />
Invalid settings file path (OK on server undeploy)<br />
<br />
I traced it to the SettingsFilePath parameter being blank which is created during the MSBUILD process. <br />
<br />
It took me a while to realise it was because the Install Wizard with 5.5 does not prompt for the location of the Settings File as it did in previous versions. It now prompts for the account name used for configuring FILE Send and Receive Ports because it will now automatically create the file locations for you and set up permissions (hooray).<br />
<br />
To solve the "Invalid settings file path" problem I had to edit the InstallWizard.XML file and add a new SetEnvUIConfigItem section to prompt for the settings file. You can find the XML in the BTDF documentation. After that, my deployment worked without error.<br />
<br />
Another point is the BTDFPROF sample file has changed and it specifies several PropertyGroup sections where the name of the BizTalkHosts are specified. I found this didn't work so I went back to adding the BizTalkHosts element in the ItemGroup section and included the host instance names I wanted to bounce. <br />
<br />
<br />
Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0tag:blogger.com,1999:blog-7178802206594541796.post-72671529006833406552014-01-23T17:15:00.001+00:002014-02-04T22:49:21.396+00:00Convert FetchXML results to XML. <span style="font-family: Arial, Helvetica, sans-serif;">With the earlier versions of Dynamics CRM you could construct FetchXML queries and the results would be returned as XML. I liked that feature but is has been deprecated in later releases. I had a need for this again recently because I wanted to get data from CRM in a format where it was easy to mail merge. I'm a big fan of Aspose Words for .Net as I have used it several times in the past with great success. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Aspose has the advantage of being able to design normal mail merge templates in Word so it is easy for a user to amend the template. Aspose uses mail merge fields just as the typical mail merge template does but you just add them manually to your template rather than from a data source. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Aspose uses data tables as the data source and I wanted a way to convert the results of a FetchXML query into a data table so it was ready to mail merge. In fact because Aspose can merge multiple data tables I need to create a dataset which I will convert to an XML string using GetXml().</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">A key factor was I wanted the code to be entirely ignorant of the columns in the result set. I want to be able to select any number of columns from a CRM entity, use lookup values and pick lists and columns from related tables. Unfortunately when querying pick lists you only get the value and not the text. You will need another method to get the text equivalent. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">I am not detailing how I do the Aspose merge in this post. It should be easy enough if you follow their samples. Just remember for this approach to work, the field names in the data table need to be unique. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">To get started I used the CRMSVCUTL.EXE utility to generate the classes of the custom entities.</span><br />
<br />
<span style="font-family: "Trebuchet MS", sans-serif;">crmsvcutil /url:http://localhost:5555/Org1/XRMServices/2011/Organization.svc </span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">/out:Xrm.cs /namespace:Xrm /serviceContextName:XrmServiceContext</span><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">I added the Xrm.cs to my project and references to Microsoft.Xrm.Sdk.dll and Microsoft.Xrm.Client.dll which can be found in the SDK\bin directory. I also added System.RunTime.Serialization and System.Data. The connection string for CRM I added to the app.config. I have tried this code on Dynamics CRM 2011 and CRM 2013 and it works fine.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<br />
<span style="font-family: "Trebuchet MS", sans-serif;"><span style="color: blue;"><span style="color: blue;">using</span></span> System;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> System.Collections.Generic;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> System.Configuration;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> System.Data;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> System.Linq;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> System.Text;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Microsoft.Xrm.Sdk;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Microsoft.Xrm.Sdk.Messages;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Microsoft.Xrm.Sdk.Metadata;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Microsoft.Xrm.Sdk.Query;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Microsoft.Xrm.Sdk.Client;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Microsoft.Xrm.Client;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Microsoft.Xrm.Client.Services;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;">
<span style="color: blue;"><span style="color: blue;">using</span></span> Xrm;</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> </span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> static IOrganizationService _service;<br /> static OrganizationService _orgService;<br /> static string FetchExpression()<br /> {<br /> <br /> String connectionString = ConfigurationManager.AppSettings["xrmConnectionString"];</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> // Establish a connection to the organization web service using CrmConnection.<br /> Microsoft.Xrm.Client.CrmConnection connection = CrmConnection.Parse(connectionString);</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> // Obtain an organization service proxy.<br /> // The using statement assures that the service proxy will be properly disposed.<br /> using (_orgService = new OrganizationService(connection))<br /> {<br /> string fetchquery = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><br /> <entity name='contact'><br /> <attribute name='fullname' /><br /> <attribute name='new_referencenumber' /><br /> <attribute name='new_locationid' /><br /> <attribute name='contactid' /><br /> <attribute name='new_contactmechanism' /> <br /> <order attribute='fullname' descending='false' /><br /> <filter type='and'><br /> <condition attribute='statecode' operator='eq' value='0' /><br /> <condition attribute='fullname' operator='not-null' /><br /> </filter><br /> <link-entity name='systemuser' from='systemuserid' to='owninguser' visible='false' link-type='outer' alias=user'><br /> <attribute name='domainname' /><br /> </link-entity><br /> </entity><br /> </fetch>";</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> _service = (IOrganizationService)_orgService;<br /> RetrieveMultipleRequest req = new RetrieveMultipleRequest();<br /> <br /> FetchExpression fetch = new FetchExpression(fetchquery);<br /> req.Query = fetch;<br /> RetrieveMultipleResponse resp = (RetrieveMultipleResponse)_service.Execute(req);<br /> <br /> // Create a dataset and datatable<br /> DataSet results = new DataSet("Results");<br /> DataTable Table1 = new DataTable("SingleRowTable");<br /> DataColumn column;<br /> DataRow workRow;</span><br />
<br />
<span style="font-family: "Trebuchet MS", sans-serif;"> foreach (Entity entity in resp.EntityCollection.Entities)<br /> {<br /> //create the columns in the data table<br /> foreach (KeyValuePair<String, Object> attribute in entity.Attributes)<br /> {<br /> column = new DataColumn();<br /> switch (attribute.Value.GetType().Name)<br /> {<br /> case "AliasedValue":<br /> column.DataType = entity.GetAttributeValue<AliasedValue>(attribute.Key).Value.GetType();<br /> break;<br /> case "EntityReference":<br /> column.DataType = entity.GetEntityReferenceValue<EntityReference>(attribute.Key).Name.GetType();<br /> break;<br /> case "OptionSetValue":<br /> column.DataType = entity.GetAttributeValue<OptionSetValue>(attribute.Key).Value.GetType();<br /> break;<br /> default :<br /> column.DataType = attribute.Value.GetType();<br /> break;<br /> }</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> column.ColumnName = attribute.Key;<br /> Table1.Columns.Add(column);</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> }<br /> // add the values to the row<br /> workRow = Table1.NewRow();<br /> foreach (KeyValuePair<String, Object> attribute in entity.Attributes)<br /> {<br /> switch (attribute.Value.GetType().Name)<br /> {<br /> case "AliasedValue":<br /> workRow[attribute.Key] = entity.GetAttributeValue<AliasedValue>(attribute.Key).Value;<br /> break;<br /> case "EntityReference":<br /> workRow[attribute.Key] = entity.GetEntityReferenceValue<EntityReference>(attribute.Key).Name;<br /> break;<br /> case "OptionSetValue":<br /> workRow[attribute.Key] = entity.GetAttributeValue<OptionSetValue>(attribute.Key).Value;<br /> break;<br /> default:<br /> workRow[attribute.Key] = attribute.Value;<br /> break;<br /> }</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> }<br /> Table1.Rows.Add(workRow);<br /> // only one row expected so exit<br /> break;<br /> }<br /> results.Tables.Add(Table1);<br /> return results.GetXml();<br /> }<br /> }</span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"> </span><br />
<span style="font-family: Consolas;"><span style="font-family: Arial, Helvetica, sans-serif;">The results are in a very simple XML structure and already to use for the mail merge.</span> </span><br />
<span style="font-family: Consolas;"></span><br />
<span style="font-family: "Trebuchet MS", sans-serif;"><Results><br /> <SingleRowTable><br /> <fullname>Adam Ant</fullname><br /> <new_referencenumber>PSN-00000286</new_referencenumber><br /> <new_locationid>Brighton</new_locationid><br /> <contactid>2d31f962-5f44-e211-ae45-00155d010a10</contactid><br /> <new_contactmechanism>100000009</new_contactmechanism><br /> <user.domainname>MSCRM2011\Administrator</user.domainname><br /> </SingleRowTable><br /></Results></span><br />
<span style="font-family: Consolas;"></span><br />Charles Emeshttp://www.blogger.com/profile/11238782194888451239noreply@blogger.com0