Tuesday, April 26, 2011

How to: Use Retrieve Messages in Jscript and .NET With the Microsoft Dynamics CRM 2011 SDK

Here is a quick demo on how to utilize the Retrieve message of the CRM 2011 Organization service in both C# and Jscript. I will provide two examples.  The first is a simple retrieve of a single entity by it's id.  The second retrieve request will navigate a relationship to retrieve not only the same contact entity, but also all the accounts for which that contact is associated.

CALL # 1



The first call will just be a simple retrieve that returns a contact entity based on it's ID GUID.
NOTE: In .NET you can then examine the Entity attribute of the response to get the main entity, and also iterate through the Entity.RelatedEntities attribute to access the related accounts.
First in C#:


      RetrieveRequest req = new RetrieveRequest();
      req.ColumnSet = new ColumnSet(true);
      req.Target = new EntityReference
      {
          Id = new Guid("007889EB-0B70-E011-8DD8-1CC1DEE8EA59"),
          LogicalName = "contact"

      };
      RetrieveResponse response = (RetrieveResponse)service.Execute(req);


Now here is the Jscript nicely formatted by the CRM 2011 SOAP formatter. Available at: http://crm2011soap.codeplex.com/

To understand how to parse the response please review my post on using the DOM parser.
http://mileyja.blogspot.com/2011/03/microsoft-dynamics-crm-2011-parsing.html

This example is asynchronous, if you want to learn how to make JScript SOAP calls synchronously please visit this posthttp://mileyja.blogspot.com/2011/07/using-jscript-to-access-soap-web.html



//main entry point
function runme() {
   SDK.SAMPLES.RetrieveContactRequest();
}

if (typeof (SDK) == "undefined")
   { SDK = { __namespace: true }; }
       //This will establish a more unique namespace for functions in this library. This will reduce the 
       // potential for functions to be overwritten due to a duplicate name when the library is loaded.
       SDK.SAMPLES = {
           _getServerUrl: function () {
               ///<summary>
               /// Returns the URL for the SOAP endpoint using the context information available in the form
               /// or HTML Web resource.
               ///</summary>
               var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
               var serverUrl = "";
               if (typeof GetGlobalContext == "function") {
                   var context = GetGlobalContext();
                   serverUrl = context.getServerUrl();
               }
               else {
                   if (typeof Xrm.Page.context == "object") {
                         serverUrl = Xrm.Page.context.getServerUrl();
                   }
                   else
                   { throw new Error("Unable to access the server URL"); }
                   }
                  if (serverUrl.match(/\/$/)) {
                       serverUrl = serverUrl.substring(0, serverUrl.length - 1);
                   } 
                   return serverUrl + OrgServicePath;
               }, 
           RetrieveContactRequest: function () {
               var requestMain = ""
               requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
               requestMain += "  <s:Body>";
               requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
               requestMain += "      <request i:type=\"a:RetrieveRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
               requestMain += "        <a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <b:key>Target</b:key>";
               requestMain += "            <b:value i:type=\"a:EntityReference\">";
               requestMain += "              <a:Id>007889eb-0b70-e011-8dd8-1cc1dee8ea59</a:Id>";
               requestMain += "              <a:LogicalName>contact</a:LogicalName>";
               requestMain += "              <a:Name i:nil=\"true\" />";
               requestMain += "            </b:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <b:key>ColumnSet</b:key>";
               requestMain += "            <b:value i:type=\"a:ColumnSet\">";
               requestMain += "              <a:AllColumns>true</a:AllColumns>";
               requestMain += "              <a:Columns xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />";
               requestMain += "            </b:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "        </a:Parameters>";
               requestMain += "        <a:RequestId i:nil=\"true\" />";
               requestMain += "        <a:RequestName>Retrieve</a:RequestName>";
               requestMain += "      </request>";
               requestMain += "    </Execute>";
               requestMain += "  </s:Body>";
               requestMain += "</s:Envelope>";
               var req = new XMLHttpRequest();
               req.open("POST", SDK.SAMPLES._getServerUrl(), true)
               // Responses will return XML. It isn't possible to return JSON.
               req.setRequestHeader("Accept", "application/xml, text/xml, */*");
               req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
               req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
               var successCallback = null;
               var errorCallback = null;
               req.onreadystatechange = function () { SDK.SAMPLES.RetrieveContactResponse(req, successCallback, errorCallback); };
               req.send(requestMain);
           },
       RetrieveContactResponse: function (req, successCallback, errorCallback) {
               ///<summary>
               /// Recieves the assign response
               ///</summary>
               ///<param name="req" Type="XMLHttpRequest">
               /// The XMLHttpRequest response
               ///</param>
               ///<param name="successCallback" Type="Function">
               /// The function to perform when an successfult response is returned.
               /// For this message no data is returned so a success callback is not really necessary.
               ///</param>
               ///<param name="errorCallback" Type="Function">
               /// The function to perform when an error is returned.
               /// This function accepts a JScript error returned by the _getError function
               ///</param>
               if (req.readyState == 4) {
               if (req.status == 200) {
               if (successCallback != null)
               { successCallback(); }
               }
               else {
                   errorCallback(SDK.SAMPLES._getError(req.responseXML));
               }
           }
       },
       _getError: function (faultXml) {
           ///<summary>
           /// Parses the WCF fault returned in the event of an error.
           ///</summary>
           ///<param name="faultXml" Type="XML">
           /// The responseXML property of the XMLHttpRequest response.
           ///</param>
           var errorMessage = "Unknown Error (Unable to parse the fault)";
           if (typeof faultXml == "object") {
               try {
                   var bodyNode = faultXml.firstChild.firstChild;
                   //Retrieve the fault node
                   for (var i = 0; i < bodyNode.childNodes.length; i++) {
                       var node = bodyNode.childNodes[i];
                       //NOTE: This comparison does not handle the case where the XML namespace changes
                       if ("s:Fault" == node.nodeName) {
                       for (var j = 0; j < node.childNodes.length; j++) {
                           var faultStringNode = node.childNodes[j];
                           if ("faultstring" == faultStringNode.nodeName) {
                               errorMessage = faultStringNode.text;
                               break;
                           }
                       }
                       break;
                   }
               }
           }
           catch (e) { };
        }
        return new Error(errorMessage);
     },
 __namespace: true
};


CALL # 2


The sample call I will use will retrieve a contact entity and all related account entities based on the "contact_customer_accounts" relationship.

NOTE: In .NET you can then examine the Entity attribute of the response to get the main entity, and also iterate through the Entity.RelatedEntities attribute to access the related accounts.
First in C#:

RetrieveRequest req = new RetrieveRequest();

      QueryExpression query = new QueryExpression();
      query.EntityName = "account";
      query.ColumnSet = new ColumnSet(true);
      Relationship relationship = new Relationship();

      query.Criteria = new FilterExpression();
      // name of relationship between team & systemuser
      relationship.SchemaName = "contact_customer_accounts";
      RelationshipQueryCollection relatedEntity = new RelationshipQueryCollection();
      relatedEntity.Add(relationship, query);
      RetrieveRequest request = new RetrieveRequest();
      request.RelatedEntitiesQuery = relatedEntity;
      request.ColumnSet = new ColumnSet(true);
      request.Target = new EntityReference
      {
          Id = new Guid("007889EB-0B70-E011-8DD8-1CC1DEE8EA59"),
          LogicalName = "contact"

      };
      RetrieveResponse response = (RetrieveResponse)service.Execute(request);

Now here is the Jscript nicely formatted by the CRM 2011 SOAP formatter. Available at: http://crm2011soap.codeplex.com/

To understand how to parse the response please review my post on using the DOM parser.
http://mileyja.blogspot.com/2011/03/microsoft-dynamics-crm-2011-parsing.html



//main entry point
function runme() {
   SDK.SAMPLES.RetrieveRelatedContactsRequest();
}

if (typeof (SDK) == "undefined")
   { SDK = { __namespace: true }; }
       //This will establish a more unique namespace for functions in this library. This will reduce the 
       // potential for functions to be overwritten due to a duplicate name when the library is loaded.
       SDK.SAMPLES = {
           _getServerUrl: function () {
               ///<summary>
               /// Returns the URL for the SOAP endpoint using the context information available in the form
               /// or HTML Web resource.
               ///</summary>
               var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
               var serverUrl = "";
               if (typeof GetGlobalContext == "function") {
                   var context = GetGlobalContext();
                   serverUrl = context.getServerUrl();
               }
               else {
                   if (typeof Xrm.Page.context == "object") {
                         serverUrl = Xrm.Page.context.getServerUrl();
                   }
                   else
                   { throw new Error("Unable to access the server URL"); }
                   }
                  if (serverUrl.match(/\/$/)) {
                       serverUrl = serverUrl.substring(0, serverUrl.length - 1);
                   } 
                   return serverUrl + OrgServicePath;
               }, 
           RetrieveRelatedContactsRequest: function () {
               var requestMain = "";
               requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
               requestMain += "  <s:Body>";
               requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
               requestMain += "      <request i:type=\"a:RetrieveRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
               requestMain += "        <a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <b:key>Target</b:key>";
               requestMain += "            <b:value i:type=\"a:EntityReference\">";
               requestMain += "              <a:Id>007889eb-0b70-e011-8dd8-1cc1dee8ea59</a:Id>";
               requestMain += "              <a:LogicalName>contact</a:LogicalName>";
               requestMain += "              <a:Name i:nil=\"true\" />";
               requestMain += "            </b:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <b:key>ColumnSet</b:key>";
               requestMain += "            <b:value i:type=\"a:ColumnSet\">";
               requestMain += "              <a:AllColumns>true</a:AllColumns>";
               requestMain += "              <a:Columns xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />";
               requestMain += "            </b:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <b:key>RelatedEntitiesQuery</b:key>";
               requestMain += "            <b:value i:type=\"a:RelationshipQueryCollection\">";
               requestMain += "              <a:KeyValuePairOfRelationshipQueryBaseX_PsK4FkN>";
               requestMain += "                <b:key>";
               requestMain += "                  <a:PrimaryEntityRole i:nil=\"true\" />";
               requestMain += "                  <a:SchemaName>contact_customer_accounts</a:SchemaName>";
               requestMain += "                </b:key>";
               requestMain += "                <b:value i:type=\"a:QueryExpression\">";
               requestMain += "                  <a:ColumnSet>";
               requestMain += "                    <a:AllColumns>true</a:AllColumns>";
               requestMain += "                    <a:Columns xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />";
               requestMain += "                  </a:ColumnSet>";
               requestMain += "                  <a:Criteria>";
               requestMain += "                    <a:Conditions />";
               requestMain += "                    <a:FilterOperator>And</a:FilterOperator>";
               requestMain += "                    <a:Filters />";
               requestMain += "                  </a:Criteria>";
               requestMain += "                  <a:Distinct>false</a:Distinct>";
               requestMain += "                  <a:EntityName>account</a:EntityName>";
               requestMain += "                  <a:LinkEntities />";
               requestMain += "                  <a:Orders />";
               requestMain += "                  <a:PageInfo>";
               requestMain += "                    <a:Count>0</a:Count>";
               requestMain += "                    <a:PageNumber>0</a:PageNumber>";
               requestMain += "                    <a:PagingCookie i:nil=\"true\" />";
               requestMain += "                    <a:ReturnTotalRecordCount>false</a:ReturnTotalRecordCount>";
               requestMain += "                  </a:PageInfo>";
               requestMain += "                  <a:NoLock>false</a:NoLock>";
               requestMain += "                </b:value>";
               requestMain += "              </a:KeyValuePairOfRelationshipQueryBaseX_PsK4FkN>";
               requestMain += "            </b:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "        </a:Parameters>";
               requestMain += "        <a:RequestId i:nil=\"true\" />";
               requestMain += "        <a:RequestName>Retrieve</a:RequestName>";
               requestMain += "      </request>";
               requestMain += "    </Execute>";
               requestMain += "  </s:Body>";
               requestMain += "</s:Envelope>";
               var req = new XMLHttpRequest();
               req.open("POST", SDK.SAMPLES._getServerUrl(), true)
               // Responses will return XML. It isn't possible to return JSON.
               req.setRequestHeader("Accept", "application/xml, text/xml, */*");
               req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
               req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
               var successCallback = null;
               var errorCallback = null;
               req.onreadystatechange = function () { SDK.SAMPLES.RetrieveRelatedContactsResponse(req, successCallback, errorCallback); };
               req.send(requestMain);
           },
       RetrieveRelatedContactsResponse: function (req, successCallback, errorCallback) {
               ///<summary>
               /// Recieves the assign response
               ///</summary>
               ///<param name="req" Type="XMLHttpRequest">
               /// The XMLHttpRequest response
               ///</param>
               ///<param name="successCallback" Type="Function">
               /// The function to perform when an successfult response is returned.
               /// For this message no data is returned so a success callback is not really necessary.
               ///</param>
               ///<param name="errorCallback" Type="Function">
               /// The function to perform when an error is returned.
               /// This function accepts a JScript error returned by the _getError function
               ///</param>
               if (req.readyState == 4) {
               if (req.status == 200) {
               //***********************
               //   ALERT RESULT HERE
               //***********************
                    alert(req.responseXML.xml.toString());
               }
               else {
                   errorCallback(SDK.SAMPLES._getError(req.responseXML));
               }
           }
       },
       _getError: function (faultXml) {
           ///<summary>
           /// Parses the WCF fault returned in the event of an error.
           ///</summary>
           ///<param name="faultXml" Type="XML">
           /// The responseXML property of the XMLHttpRequest response.
           ///</param>
           var errorMessage = "Unknown Error (Unable to parse the fault)";
           if (typeof faultXml == "object") {
               try {
                   var bodyNode = faultXml.firstChild.firstChild;
                   //Retrieve the fault node
                   for (var i = 0; i < bodyNode.childNodes.length; i++) {
                       var node = bodyNode.childNodes[i];
                       //NOTE: This comparison does not handle the case where the XML namespace changes
                       if ("s:Fault" == node.nodeName) {
                       for (var j = 0; j < node.childNodes.length; j++) {
                           var faultStringNode = node.childNodes[j];
                           if ("faultstring" == faultStringNode.nodeName) {
                               errorMessage = faultStringNode.text;
                               break;
                           }
                       }
                       break;
                   }
               }
           }
           catch (e) { };
        }
        return new Error(errorMessage);
     },
 __namespace: true
};


Now you can call the runme function from your form jscript handler.
Thats all there is to it!

I hope this helps!

1 comment:

  1. Wow is good to be back with my ex again, thank you Dr Ekpen for the help, I just want to let you know that is reading this post in case you are having issues with your lover and is leading to divorce and you don’t want the divorce, Dr Ekpen is the answer to your problem. Or you are already divorce and you still want him/her contact Dr Ekpen the spell caster now on (ekpentemple@gmail.com) and you will be clad you did

    ReplyDelete