We will now take a look at a more complex subject: writing an external application that will interact with the CRM API. To help explain how the CRM API works we will walk you through writing an application that will interact with the CRM platform. We'll try to provide general guidelines for creating other customizations, including ASPX pages that integrate into the standard Microsoft CRM application or an external application. However, our goal is not to have an in-depth discussion or to introduce every method of every object of the API. For more information on these topics, consult the Microsoft CRM SDK documentation that is available online on MSDN.
First of all, it's important to note that the CRM platform is made available as a collection of Web services. This means that the platform can be accessed from a multitude of platforms, environments, and languages—such as Linux, Java, or Perl. However, we will focus on using C# on the Windows .NET platform in our examples. Also, as long as the Microsoft CRM Web server is available to visitors on the Internet, it is possible to make calls to those Web services from anywhere provided that the calling application has been successfully authenticated.
Now let's talk about the actual application that we will build in this section. To implement our own installation of Microsoft CRM, we needed to import numerous contacts from a number of Outlook pst files. At that time, the Microsoft import tool was not yet available, and no third-party product was available to help us import the data. We looked at the import functionality that was available in the Web client, but because it was not designed to import all .pst fields (for example, notes and categories), we made the decision to write our own import tool.
What we needed was to create a Contact in Microsoft CRM for each Contact in the .pst file. We also needed to create a note linked to the Contact if there was anything in the Outlook note area on the Contact screen. Finally, we needed to create an Account, if one didn't already exist, for the contact's employer and link the two records.
The first thing we did was to setup a new C# project in Visual Studio to build the interface. In the interface, we wanted the user to be able to specify the name of the CRM server where the data needed to be imported before starting the import process. Finally, we wanted to offer some visual feedback on the import progress. Figure 14.3 shows the interface of our Outlook data import tool.
NOTELooking at Figure 14.3, notice that in addition to the server name text box, there is a text box to capture the service name. This refers to the virtual directory under which the different CRM services are made available on your Web server. MSCRMServices is the default value, but an administrator could decide to change this name. For this reason, it may be desirable to allow users to specify this value in applications that need to connect to a Microsoft CRM server. |
The full source code for the import tool is available on the CD accompanying the book in the Chapter ExamplesChapter 14c360 Import Outlook Data folder. Here we will limit our discussion to the code that is relevant to the CRM API.
There are a couple of prerequisites to running our customization. First, Microsoft Outlook must be installed and running on the PC on which the import tool is to be runned. Second, our new C# project needs references to different libraries (or DLLs) to help us talk to different APIs. More specifically, we need a reference to the Outlook library as well as a reference to the Microsoft.CRM.Proxy.dll. The Outlook library is installed when Microsoft Office is installed. The Microsoft.CRM.Proxy.dll file is either on the Microsoft CRM CD or on the InetPubwwwrootin folder on the Web server where Microsoft CRM is installed. Both of these files have been included on the accompanying CD.
This is where the bulk of the work is done. We've divided this discussion into multiple sections for simplification. We will discuss each section and present the most important lines of code in each.
The first thing worth noting here is that we capture the server and service name entered by the user, format it as a URL, and store it in a variable for future reference:
string strDir = "http://" + _form.ServerName + "/" + _form.ServiceName + "/";
The second important thing is the declaration of the various CRM objects. Let's take the Account object for example:
We start by creating a new instance of this object in memory:
Microsoft.CRM.Proxy.CRMAccount objCrmAccount = new Microsoft.CRM.Proxy.CRMAccount();
Next, we forward the current user's credentials by using the .NET framework's DefaultCredentials property on the CredentialCache object:
objCrmAccount.Credentials = System.Net.CredentialCache.DefaultCredentials;
Finally, we set the URL to the Web service:
objCrmAccount.Url = strDir + "CRMAccount.srf";
In this section we create five different CRM objects. Table 14.2 contains a brief description of each:
It's now time to validate the user's credentials and find the CRM user to which they are linked. First, we'll create an instance of the BizUser:
Microsoft.CRM.Proxy.BizUser objCrmUser = new Microsoft.CRM.Proxy.BizUser(); objCrmUser.Credentials = System.Net.CredentialCache.DefaultCredentials; objCrmUser.Url = strDir + "BizUser.srf";
Next, we need to call the WhoAmI method so that the platform can figure out which CRM user the given credentials map to. The method returns a UserAuth object, which we need to save for future reference. If the current user doesn't have a valid CRM user or wasn't granted a license, the call will fail:
Microsoft.CRM.Proxy.CUserAuth objUserAuth = objCrmUser.WhoAmI();
The next task is to get a reference to the Outlook contacts we will import and also fetch the first contact from that list:
Outlook.ApplicationClass objOutlook = new Outlook.ApplicationClass(); Outlook.Items objContacts = objOutlook.GetNamespace("MAPI").Folders.Item("CRM Contacts").Folders.Item("Contacts").Items; Outlook.ContactItem objContact = (Outlook.ContactItem) objContacts.GetFirst();
The Outlook folder containing the contacts is called CRM Contacts. This will likely be different from system to system, so it is necessary to adjust the code accordingly.
We can now create the Account record. However, we first need to verify that the company name on the Outlook contact is not empty because it would indicate that the contact is not linked to an Account. Also, we need to verify if that company already exists. We used the company's name in our verification, but you could modify this logic and use a different matching rule (for example, the first 10 letters of the company name as well as the company's state code).
if ((objContact.CompanyName != null) && (objContact.CompanyName != String.Empty)) { strXml = new StringBuilder(); strXml.Append("<fetch><entity name='Account'><attribute name='accountid'/> <filtertype='and'><condition attribute='name' operator='eq' value='"); strXml.Append(HtmlEncode(objContact.CompanyName)); strXml.Append("'/></filter></entity></fetch>"); objXmlDoc.LoadXml(objCrmQuery.ExecuteQuery(objUserAuth, strXml.ToString())); objNode = objXmlDoc.SelectSingleNode("//accountid"); bAccountExist = (objNode != null);
The second parameter passed to the ExecuteQuery method is a FetchXml string. FetchXml is a flexible and powerful query language for Microsoft CRM. FetchXML enables the execution of advanced queries against the CRM data.
In the interest of brevity, we'll skip the section of code where we build the string that enables us to create new Accounts. However, it is of interest to note where we got the list of available fields on the Account object. This can be found by looking at the Create method of the CRMAccount in the SDK documentation and click the link to the Account.xsd. This links to a page of all the standard fields and whether they can be used when creating a new Account or updating an existing Account.
Now creating the Account is a simple matter of calling the Create method. This method returns the Id of the newly created account, which we need to save for future reference.
strAccountId = objCrmAccount.Create(objUserAuth, strXml.ToString());
The following section creates the contact and is structured the same way as the previous example. Look closely at the following lines that allow us to link the Account to this Contact as the Parent Account. This link, however, is not bidirectional. In other words, it does not link the Contact back to the Account. We will take care of this other link in the next section.
if ((objContact.CompanyName != null) && (objContact.CompanyName != String.Empty)) { strXml.Append("<accountid>"); strXml.Append(strAccountId); strXml.Append("</accountid>"); }
Next, we complete the link between the Contact and the Account records by updating the Account's primarycontactid field only on new Accounts. We assume that existing Accounts already have a primary contact, which we don't want to overwrite.
if (!bAccountExist) { strXml = new StringBuilder(); strXml.Append("<account>"); strXml.Append("<primarycontactid>"); strXml.Append(strContactId); strXml.Append("</primarycontactid>"); strXml.Append("</account>"); objCrmAccount.Update(objUserAuth, strAccountId, strXml.ToString()); }
The last two tasks are to create a second address if one was provided on the Outlook contact and create a note if necessary.
The rest of the code takes care of updating the progress bar and fetching the next Outlook contact.
objContact = (Outlook.ContactItem) objContacts.GetNext();
We have now completed our application. We were able to communicate, from an external application, with the CRM API by using the available Web Services. All the services are very similar to each other (for example, Account, Note, Address, and so on), so knowing how to use one makes it simple to use any of the others.
3.141.42.12