Creating a CallOut for MS CRM 3.0
A couple of weeks ago we had to do a proof of concept with BizTalk Server, Microsoft CRM and SAP. The proof of concept consisted of several parts. This blog entry will focus on the part where data has to be read from MS CRM.
The scenario we needed to implement was a follows:
1. Create account in MS CRM
2. Write account in SAP
3. Send e-mail to creator
In order to get account data out of MS CRM 3.0 and into BizTalk Server we used the CallOut mechanism. We first tried to use the BizTalk adapter for CRM, but it seems that this adapter only supports write (create, update, delete) actions. We haven’t found read actions in this adapter.
So CallOuts. As a BizTalk designer I was not too happy about the prospect of creating CallOut code. But it turned out quite simple. I found several pieces of sample code which I combined. And then with a little code of my own, it did everything we needed it to do. Plus it is event based, which is doesn’t have the timing or performance problems of polling.
At first we had to install Visual Studio 2003 on a machine that could connect to the CRM server. Visual Studio 2003 was needed to create .Net 1.1 assemblies. And the connection to the CRM server was needed to set the correct web reference. The code we started with was the calloutsample2 from the Microsoft CRM 3.0 SDK.
In order to get the e-mail of the person who created or modified the CRM record, we needed more data than that was available in the PostCreate account entity. We got a GUID of the person, but in order to get the e-mail address, we had to add a call to the CRM web service. The code to retrieve the e-mail (internalemailaddress) is listed in code snippit 1.
Bottom-line, to create a CallOut in CRM 3.0 for BizTalk to use you need to do the following.
1. Install Visual Studio 2003 on a PC with a network connection to the CRM Server.
2. Install the Microsoft CRM 3.0 SDK
3. Open the calloutsample2 project from the sdk
4. Paste the code snippits below in the calloutassembly.cs file
5. Set a reference to Microsoft.Crm.Platform.Callout.Base.dll
(Browse to the dll file)
6. Set a web reference to the CRM web service
(http://CRMSERVER/mscrmservices/2006/crmservice.asmx)
7. Compile
8. Modify the sample callout.config.xml
(remove what you don’t need)
9. Stop the IIS services on the CRM Server
10. Paste the created dll file into the C:\Program Files\CRM Server\server\assembly directory.
11. Paste the modified callout.config.xml file into the C:\Program Files\CRM Server\server\assembly directory.
12. Start the IIS services on the CRM Server
13. Restart the MS CRM Workflow service on the CRM Server
14. Done.
Start creating accounts and watch them appear in your file share.
There still is room for improvement for this piece of code. J
We now post files on a file share. To guarantee delivery of our messages MSMQ would be better.
public override void PostCreate(
CalloutUserContext userContext,
CalloutEntityContext entityContext,
String postImageEntityXml
)
{
XmlDocument xd = new XmlDocument();
xd.LoadXml(postImageEntityXml);
switch(entityContext.EntityTypeCode)
{
case (int)EntityName.account:
foreach(XmlElement element in
xd.GetElementsByTagName("Property"))
{
if(element.Attributes.GetNamedItem("Name").Value == "modifiedby")
{
// Set up the CRM Service.
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create the column set object that indicates the fields to be retrieved.
ColumnSet cols = new ColumnSet();
// Set the properties of the column set.
cols.Attributes = new string [] {"internalemailaddress"};
// Create the target object for the request.
TargetRetrieveSystemUser target = new TargetRetrieveSystemUser();
// Set the properties of the target object.
// EntityId is the GUID of the record being retrieved.
target.EntityId = new Guid(GetID(element.FirstChild.InnerText));
// Create the request object.
RetrieveRequest retrieve = new RetrieveRequest();
// Set the properties of the request object.
retrieve.Target = target;
retrieve.ColumnSet = cols;
// Execute the request.
RetrieveResponse retrieved = (RetrieveResponse)service.Execute(retrieve);
CrmSdk.systemuser user = (systemuser) retrieved.BusinessEntity;
element.FirstChild.InnerText = user.internalemailaddress + element.InnerText;
WriteToFile(String.Format("\r\nCreate\r\n{0}\r\n\r\n\r\n{1}\r\n\r\n",RemoveNameSpace(postImageEntityXml), user.internalemailaddress));
}
}
break;
}
}
|
Code snippit 1: PostCreate()
private String RemoveNameSpace(String source)
{
int i, j;
String dest = String.Copy(source);
String temp;
do
{
// start xsi:
i = dest.IndexOf("xmlns");
// end xsi:
temp = dest.Substring(i+12);
j = temp.IndexOf("\"");
if(i != -1)
dest = String.Concat(dest.Substring(0, i), dest.Substring( i+12+j+1));
} while(i != -1);
do
{
// start xsi:
i = dest.IndexOf("xsi: ");
// end xsi:
temp = dest.Substring(i+10);
j = temp.IndexOf("\"");
if(i != -1)
dest = String.Concat(dest.Substring(0, i), dest.Substring( i+10+j+1));
} while(i != -1);
return dest;
}
|
Code snippit 2: RemoveNameSpace()
private string GetID(string id)
{
//string adminID = "{56EEDA2E-D27F-DA11-B5D0-0003FF0BBE00}";
string adminID = id;
adminID = adminID.Replace("{", "");
adminID = adminID.Replace("}", "");
//WriteToFile(adminID);
return adminID;
}
|
Code snippit 3: GetID()
The configuration file that we used was as in the sample sdk. We only removed the callout entities that we had not implemented.
C:\Program Files\CRM Server\server\assembly\callout.config.xml
Authors
Marcel Fernee: marcel.fernee@microsoft.com
Henry Osagiede: henry.osagiede@atosorigin.com
Mark Wijngaarden: mark.wijngaarden@atosorigin.com
Mariette Mak: mariette.mak@atosorigin.com
Resources
Information on CallOuts in CRM 3.0
http://msdn2.microsoft.com/en-us/library/aa682477.aspx
Debugging Callouts
http://msdn2.microsoft.com/en-us/library/aa681366.aspx
Microsoft CRM 3.0 SDK
http://www.microsoft.com/downloads/details.aspx?familyid=9C178B68-3A06-4898-BC83-BD14B74308C5&displaylang=en