Calling the CRM Web Service with JavaScript
Plenty of examples can be found on how to call web services with JavaScript (see here and here). With respect to CRM, almost every example lacks a good explanation of A) what the code is doing (and why), and most importantly B) what to do with the result (to be fair, the answer to this is largely dependent on what data you are retrieving). The intent of this post is to provide enough insight so that you can easily take the ideas presented here and utilize them to suit your needs.
The basic process is this:
- Connect to the web service.
- Construct and send data containing the request.
- Grab the results returned by the web service.
- Parse the results to extract the relevant data.
Connect to the CRM Web Service
In order to connect to a web service with JavaScript, we use the XMLHTTPRequest object. There are 2 ways you can create the object:
// ALL MODERN BROWSERS (INCLUDING IE 7)
var xmlhttp=new XMLHttpRequest();
// IE 5 AND 6 (INCLUDING IE 7)
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
When developing for MSCRM, the second method is preferred, unless you are certain there are no prior versions of IE in use. Now that we've created the object, we need to use the Open method to specify the web service connection we will be using. The Open method has three arguments: Method, URL, and Async. So, to connect with our CRM web service, we use the following line:
// OPEN THE CONNECTION
xmlhttp.open('GET', 'http://crmserver/mscrmservices/2006/crmservice.asmx', false);
We will be using the GET method because we are receiving data back from the web service. For the URL, simply replace "crmserver" with the your appropriate server name. Notice we set the Async argument to false. Setting this to true tells the browser to continue running the rest of the code in the background before the data is returned - that's not what we want in this case.
Construct and Send the XML Request
Okay, so we've initialized the web service connection, now what? The CRM web service accepts requests as an XML string. The structure and content of the XML you send is dependent on what type of request you are making. First, we need to set some properties of the request:
// SET REQUEST PROPERTIES
xmlhttp.setRequestHeader('Content-Type', 'text/xml; charset=utf-8');
xmlhttp.setRequestHeader('SOAPAction', 'http://schemas.microsoft.com/crm/2006/WebServices/RetrieveMultiple');
These two lines allow us to set the HTTP headers of the data that will be sent to the server. The first specifies that we are sending data in text format with utf-8 encoding. The second specifies what process (or "action") we want to carry out on the server. In this case, we want to execute the RetrieveMultiple method of the MSCRM web service. To see which methods are available, browse to 'http://crmserver/mscrmservices/2006/crmservice.asmx' (be sure to update the server name).
Now, we need to specify which data the web service should return - basically, we want to create our query. We do this by creating some XML that represents a QueryByAttribute object. The structure of the QueryByAttribute looks like this:
<? xml version='1.0' encoding='utf-8' ?>
<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<soap:Body>
<query xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:QueryByAttribute' xmlns='http://schemas.microsoft.com/crm/2006/WebServices'>
<q1:EntityName>ENTITY_NAME</q1:EntityName>
<q1:ColumnSet xsi:type="q1:ColumnSet">
<q1:Attributes>
<q1:Attribute>ATTRIBUTE1</q1:Attribute>
<q1:Attribute>ATTRIBUTE2</q1:Attribute>
</q1:Attributes>
</q1:ColumnSet>
<q1:Attributes>
<q1:Attribute>CRITERIA_ATTRIBUTE</q1:Attribute>
</q1:Attributes>
<q1:Values>
<q1:Value xsi:type="xsd:string">CRITERIA_VALUE</q1:Value>
</q1:Values>
</query>
</soap:Body>
</soap:Envelope>
This XML represents a QueryByAttribute that returns ATTRIBUTE1 and ATTRIBUTE2 from the ENTITY_NAME entity where the CRITERIA_ATTRIBUTE value equals CRITERIA_VALUE. To carry out the query, we would build a string containing the above XML structure and then use the Send() method to send that string to the web service for processing.
In a real world usage scenario, here's how we'd get a list of all Contacts from California:
// BUILD THE XML REQUEST STRING
var xmlPost = "<?xml version='1.0' encoding='utf-8'?>"+"\n\n"+"<soap:Envelope"+
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"'+
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'+
' xmlns:xsd="http://www.w3.org/2001/XMLSchema">'+
' <soap:Body>' +
' <query xmlns:q1="http://schemas.microsoft.com/crm/2006/Query" xsi:type="q1:QueryByAttribute" xmlns="http://schemas.microsoft.com/crm/2006/WebServices">'+
' <q1:EntityName>contact</q1:EntityName>'+
' <q1:ColumnSet xsi:type="q1:ColumnSet">'+
' <q1:Attributes>'+
' <q1:Attribute>contactid</q1:Attribute>'+
' <q1:Attribute>fullname</q1:Attribute>'+
' </q1:Attributes>'+
' </q1:ColumnSet>'+
' <q1:Attributes>'+
' <q1:Attribute>address1_stateorprovince</q1:Attribute>'+
' </q1:Attributes>'+
' <q1:Values>'+
' <q1:Value xsi:type="xsd:string">CA</q1:Value>'+
' </q1:Values>'+
' </query>'+
' </soap:Body>'+
' </soap:Envelope>';
// SEND THE REQUEST
xmlhttp.send(xmlPost);
Grab and Parse the Results
We've made our request, so now what? Well, we have to grab the response (remember that MSCRM utilizes the Request-Response philosophy). In order to work with the response, we create a variable to store the XML data we receive back from MSCRM:
// GET THE RESPONSE
var xmlResponse = xmlhttp.responseXML;
Now we have our return data, but we still need to parse out the XML and get the meaningful values. I've seen several different techniques to do this, and I think most of them are pretty hokey and try to parse out data manually. You know that the data is XML and not just a string, so why not use the XML functionality you already have? Not only is it more robust, but it's just easier to work with.
The above code creates the xmlResponse variable, which ends up being an XML data type. To parse this, we create an node list by using the selectNodes method of the xmlResponse object:
// PARSE NODES
var contacts = xmlResponse.selectNodes("//BusinessEntity/contactid");
var names = xmlResponse.selectNodes("//BusinessEntity/fullname");
The above code creates two lists containing all of the values found in the contactid and fullname columns of the query. If you are ever unsure of exactly how the result XML is structured, you can always output the XML string using document.write during development to give you an idea of how to construct the search strings you need to use with selectNodes().
To access these values, we simply loop through the lists:
// LOOP THROUGH VALUES
for(var i = 0; i < contacts.length; i++)
{
document.write("The contactid for ",names[i].text," is: ", contacts[i].text);
}
The above code loops through the nodes and writes data from the query.
Wrap-Up
So that's pretty much it. Hopefully I've presented enough information here to allow you to really understand how to perform MSCRM web service calls. You can call other web services with the stuff I've shown here - the main difference is MSCRM utilizes XML for the input and output, so you have to do a little more work in that respect.
How did I know how to structure the XML for the QueryByAttribute? I didn't - I just had that from one of the first examples I found online. There are few ways to figure out how you need to shape the request XML:
- Enable Tracing: This will allow you to capture and view the Request and Response SOAP messages so you can see how they are constructed (and so you know how to parse them out). You'll then have to have some activity going against CRM to generate the SOAP messages. Be sure to disable tracing when you are finished - this can really eat up some disk space.
- Take a look at the WSDL: Navigate to http://<servername>/mscrmservices/2006/crmservice.asmx?WSDL and take in the nuts and bolts in all its glory. Not for the faint of heart, but you can see how every single type is constructed.
- Use a generic SOAP client (such as XMLSpy) to inspect the request and response SOAP messages. There are many references to a free utility called .NET WebServiceStudio 2.0 that was hosted on GotDotNet, but it has since disappeared. From all accounts, it was a wonderful utility for just this kind of work.
- Last, but not least - Check out Stunnware.