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 = "http://<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", "http://schemas.microsoft.com/crm/2006/WebServices/RetrieveMultiple")
xmlhttp.send("<?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>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: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>
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,
Nick
Great 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.
We've tried this code in the CRM Web Browser client and it works fine. The Outlook client, however, fails when it reaches the "xmlhttp.open()" line. The error we receive is an "Unknown name" error.
Any ideas what may be causing this?
- Kyle
Webservices Webservices Webservices....alla pratar om dem, alla vill ha det och vi har det :) Visste
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=101
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.
Darin
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?
Thanks
Ken
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?