Microsoft Dynamics CRM Online comes with many innovations most important (in my opinion) of which is the REST (oData) endpoint that enables the developers to manipulate CRM entities with get/post requests. This not only provides the opportunity to create client-side-only (i.e. JavaScript, not Silverlight) operations for the developers, but also makes life a little easier when you compare it to the SOAP endpoints from CRM 4.0 (which still exist in CRM 2011, however only to integrate with external web sites/pages/applications*). In this elaborate set-up, the only missing thing (when comparing to CRM 4.0) is the RESTful MetaData Service endpoint.
XRM JavaScript Interface
In a usual CRM Online solution, we would normally include JavaScript files that include event handling functions according to the changes on default and/or custom entity forms. If there is any need, the solution can be extended with custom HTML pages/dialogs which helps the CRM users in executing different tasks manipulating the data. While implementing these, the developer would generally resort to Xrm properties and functions (e.g. Xrm.Page.getControl(…), Xrm.Page.getAttribute(…) …etc.).
oData and jQuery
While Xrm singleton provides access to the current entity, it does not provide the ability to edit CRM data on other entities. In this scenario, we would have to resort to the organizationdata.svc endpoint. This service endpoint accepts GET/POST requests using JavaScript and allows CRUD operations on CRM entities. One can use jQuery to execute these requests following the oData principles.
CRM $Metadata
However, when it comes to accessing the Metadata service as you would normally do on CRM 4.0 when you need to display entites or lookup values or the entity attributes in a dropdown, there is no REST endpoint in CRM 2011 (although it is in the road-map **). The only possible metada provider is the $metadata request to the organizationdata.svc. The XML file that is returned uses conceptual schema definition language (CDSL) to describe the data available which is used to generate typed classes when one is dealing with managed code in Silverlight.
<?xml version=“1.0“ standalone=“yes“?>
<Edmx Version=“1.0“>
<DataServices>
<Schema>
<EntityType Name=“SdkMessageRequestField“>
<Key>
<PropertyRef Name=“SdkMessageRequestFieldId“/>
</Key>
<Property Name=“FieldMask“ Type=“Edm.Int32“ Nullable=“true“/>
…
<NavigationProperty Name=“…“ Relationship=“…“ FromRole=“…“ ToRole=“…“/>
…
</EntityType>
<ComplexType Name=“EntityReference“>
<Property Name=“Id“ Type=“Edm.Guid“ Nullable=“true“/>
<Property Name=“LogicalName“ Type=“Edm.String“ Nullable=“true“/>
<Property Name=“Name“ Type=“Edm.String“ Nullable=“true“/>
</ComplexType>
…
So an example jQuery call that returns the CSDL xml document would look like:
// default settings
var settings = {
type: “GET”,
async: false,
url: “[CRMSERVER]/XRMServices/2011/OrganizationData.svc/$metadata”,
contentType: “application/json; charset=utf-8”,
datatype: “json”,
beforeSend: function (request) {
request.setRequestHeader(“Accept”, “application/json”);
},
error: function (XmlHttpRequest, textStatus, errorThrown) {
var error = window.JSON.parse(XmlHttpRequest.responseText);
alert(“Error : “ + textStatus + “: “ + XmlHttpRequest.statusText +
“\r\nCode : “ + error.error.code +
“\r\nMessage : “ + error.error.message.value);
}
};
var result = $.ajax(options).responseText;
Then, we can load this string representation of the XML document into an ActiveX object to treat it like an XML node.
var xmlResult = new ActiveXObject(“Microsoft.XMLDOM”);
xmlResult.loadXML(result);
At this point we have the CRM Metadata loaded into an ActiveX object in JavaScript.
Accessing CRM Metadata with JavaScript
After retrieving the XML metadata description, we have two choices, one is to traverse the XML nodes, and extract the required metadata information, or we can make our lives much easier by using an XSL transformation to transform the XML data into JSON representation.
Using the XML DOM methods and properties such as childNodes, parentNode, attributes, getElementsByTagName etc. can be painful and error prone since this metadata file actually contains a long list of complex and enitytype definitions, together with the object relations.
Fortunately, CRM Online supports web resources of type XSLT which means we can actually use a transformation to convert the XML data into JSON objects. An example xsl transformation that returns the current custom and default types, together with their attributes would look something like:
<xsl:output method=“text“ version=“1.0“ encoding=“UTF-8“ indent=“yes“/>
<xsl:preserve-space elements=“*“/>
<xsl:template match=“/“>
[<xsl:for-each select=“Edmx/DataServices/Schema/EntityType“>
{
“Name”: “<xsl:value-of select=“@Name“ />“,
“Attributes”:
[
<xsl:for-each select=“./Property“>
{
“Name”: “<xsl:value-of select=“@Name“ />“,
“Type”: “<xsl:value-of select=“@Type“ />“,
“Nullable”: <xsl:value-of select=“@Nullable“ />
},
</xsl:for-each>
]
},
</xsl:for-each>]
</xsl:template>
And the JavaScript that transforms the XML document with the XSL transformation would look like:
var xslt = new ActiveXObject(“Microsoft.XMLDOM”);
xmlResult.async = false;
xslt.async = false;
xslt.load(“../WebResources/cs_/Xsl/CrmMetadata.xslt”);
// TODO: if the function is executed in an HTML resource file, the relative link would be needed.
if (xslt.xml == “”) {
xslt.load(“Xsl/CrmMetadata.xslt”);
}
var output = xmlResult.transformNode(xslt);
var entities = eval(output);
And there you have it, the CRM entity metadata is loaded into JSON objects.
Since the metadata file is 3+ MBs, I would strongly suggest using an async methodology while sending the request and transforming the xml data.