Calling “CRM” Web services using JScript
Since I wrote the post about calling "any" web service from CRM forms (BTW, that is my most viewed post to date!), folks have written to me and asked "what the heck, what about calling “CRM” web services, hello"?
Calling CRM web services from JScript is not the best programming experience that you could imagine, mostly because it is not much fun using strongly typed classes in Jscript code (Atlas solves that problem to a great degree, more on this later) whereas you do get a great developer experience inside Visual Studio with strongly typed classes.
So there are two options to call CRM web services from CRM forms (or from any html/aspx pages using JScript) 1) use a intermediate proxy web service with a simple interface that masks the complexy of strongly typed classes. Such web service can have complex code and calls CRM web services using our WSDL. This approach may work for many of your scenarios where performance is not as critical as developer experience 2) call CRM web services directly from CRM form using SOAP messages (there is a third option to use Atlas. Michael who is one of our dev leads and I are still thinking about the best way to get that to work, stay tuned). This approach is less developer friendly to work with since you have to create a SOAP message in JScript, send it to the CRM server and parse the returned XML to get the data that you need, but it should be faster than calling teh intermediate service. Here is a sample to show you how to do this using JScript and POST.
This sample directly calls CRM web service RetrieveMultiple method and passes a QueryByAttribute object. The query condition is to retrieve all the accounts that are in the state of Washington (address1_stateorprovince = WA).
First thing I did was to enable tracing and capture the SOAP message for RetrieveMultiple passing in a QueryByAttribute. The tracing file includes both requests and responses. Next, I added the SOAP request string to my POST request on the Jscript code. I post the SOAP message to CRM web service and get the results back in xml. Then I parse the xml to extract the data that I am interested in, in this case a list of account names. Finally I write the account names on the html page that i am calling the web service from. The sample is written for a standalone html page but you can easily cut and paste the code into Onload, OnSave or OnChange event of any CRM forms.
Make sure you add your server name where it says below.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Access CRM Web Services</title>
<SCRIPT language="JavaScript">
//Call CRM web services directly
function AccessCRMWebServices()
{
var serverUrl = "https:// <ADD your Server name here> /mscrmservices/2006";
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
alert(serverUrl+ "/crmservice.asmx");
xmlhttp.open("POST", serverUrl + "/crmservice.asmx", false);
xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8")
xmlhttp.setRequestHeader("SOAPAction", "https://schemas.microsoft.com/crm/2006/WebServices/RetrieveMultiple")
xmlhttp.send("<?xml version='1.0' encoding='utf-8'?>"+"\n\n"+"<soap:Envelope"+
' xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"'+
' xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"'+
' xmlns:xsd="https://www.w3.org/2001/XMLSchema">'+
' <soap:Body>' +
' <query xmlns:q1="https://schemas.microsoft.com/crm/2006/Query" xsi:type="q1:QueryByAttribute" xmlns="https://schemas.microsoft.com/crm/2006/WebServices">'+
' <q1:EntityName>account</q1:EntityName>'+
' <q1:ColumnSet xsi:type="q1:ColumnSet">'+
' <q1:Attributes>'+
' <q1:Attribute>name</q1:Attribute>'+
' <q1:Attribute>address1_stateorprovince</q1:Attribute>'+
' </q1:Attributes>'+
' </q1:ColumnSet>'+
' <q1:Attributes>'+
' <q1:Attribute>address1_stateorprovince</q1:Attribute>'+
' </q1:Attributes>'+
' <q1:Values>'+
' <q1:Value xsi:type="xsd:string">WA</q1:Value>'+
' </q1:Values>'+
' </query>'+
' </soap:Body>'+
' </soap:Envelope>')
var result = xmlhttp.responseXML.xml;
//Separate the BusinessEntities XML tag
var BEs= result.split("<BusinessEntities>");
//Separate the BusinessEntity XML tag
var BE = BEs[1].split("<BusinessEntity");
//Walk through each Business Entity tag and extract account names
for (i = 0; i < BE.length; i++)
{
first = BE[i].indexOf("<name>")+6;
second = BE[i].indexOf("</name>");
document.writeln(BE[i].substring(first,second) + "<BR>");
}
}
//Simply call the method when the page is loaded
AccessCRMWebServices() ;
</SCRIPT>
</head>
<body>
</body>
</html>
Comments
Anonymous
August 29, 2006
PingBack from http://blogs.infinite-x.net/2006/08/29/the-crm-team-rocks-more-sample-code/Anonymous
September 03, 2006
The comment has been removedAnonymous
September 05, 2006
Josh
This will only work against the CRM server. There is no offline support in V3.0 (My bad in previous comment).Anonymous
September 14, 2006
I am trying to do the same thing with the GrantAccess method. Not having luck with the SOAP part. Any advice on how I can find out how to do this?
I am not sure how to include the PrincipalAccess information (i.e. AccessMask, prinicpal) and Target into the SOAP envelop.
Any suggestions?Anonymous
September 15, 2006
The comment has been removedAnonymous
September 17, 2006
The comment has been removedAnonymous
September 17, 2006
The comment has been removedAnonymous
October 05, 2006
Thanks for this awesome code. I was able to modify it to create a picklist of contact names for the related account on an opportunity form and thus able to have multiple contacts, ie-client contact, client executive contact, etc on the opportunity form and views. I was also able to use this method to have multiple users on a form as well (main owner, technical contact, project leader, etc) My question is this, where do you find the XML schema structure to structure the query request in XML format? I understand the "querybyattribute" structure, but what if I want to do something similar using "querybyexpression"? I can do this in a ASPX page using C# but this would run faster if I could do this in an onchange like above. I can't seem to locate this in the SDK, or am I missing something really obvious? I am just unclear of where to put/embed things like <linkedentity> and <filterexpression>, etc Thanks, NickAnonymous
October 08, 2006
NickGreat to hear you are using this. Two ways to find out about the schema and build your XML 1) use the CrmService.asmx web service WSDL, the WSDL includes the schema for QueryExpression and all of the rest of CRM types 2) Enable tracing (follow the link in the my post), make a web service call using C# and view the tracing log. The tracing log will have the SOAP XML that you need to use in your form JScript.Anonymous
October 11, 2006
The comment has been removedAnonymous
October 16, 2006
Webservices Webservices Webservices....alla pratar om dem, alla vill ha det och vi har det :) VissteAnonymous
October 17, 2006
Or you can use Microsofts own JavaScript classes (or modified versions of them) like I did here: http://www.sharepointdemo.biz/blogs/bjarne/default.aspx?BlogId=101Anonymous
October 17, 2006
Nick, Another way, one that seemed easier than the trace log, was to use a tool called WebserviceStudio. Just point to your webservice (ie. CrmService.asmx) and press a button to get all the available method in the web service. Then you can choose between a QueryExpression or QueryByAttribute, etc. Then just fill in your criteria and press another button. On the Request/Response tab will be your SOAP messages, just how you need them. Took me an hour to figure out how to use it correctly to generate the correct SOAP messgae (if you set it up wrong, you get an error). Hope this app helps you, too. DarinAnonymous
December 08, 2006
The first time the web-service is called after opening CRM, I'm being prompted with a Login. Is there any way to eliminate this?ThanksKenAnonymous
December 14, 2006
We've been using this code for quite some time and it works great. However, if we're using the Outlook Laptop Client, and we're trying to access "http://localhost:2525/MSCRMServices/2006" (the local website), the process fails.Is there a way to get this to work?Thanks,KyleAnonymous
December 18, 2006
Solution for unknown nameThe problem is, that your webservice is running on a separate website. Itshould be working fine, if you create a new virtual-directory under the CrmWebsite and try it again. (Don't forget to change the link on your formscriptto the new WS-Url ;-)If anybody is good in security topics, why does this happen and is itpossible to run the webservice on a separated website?Hope anybody can save the time I wasted...Anonymous
December 20, 2006
IE prevents calling web services that are in different domain from where the page is loaded from. This is a security feature that prevents cross-site scripting. The Outlook client uses the current machine hence it is on a seperate domain. The suggestion is to have your web service and web site both on the same domain.Anonymous
March 08, 2007
There are some good reasons why an appointment is read-only after closing it. But sometimes it couldAnonymous
March 19, 2007
Great site! Good luck to it's owner!Anonymous
May 11, 2007
The comment has been removed