Tuesday, August 2, 2011

Close a Case Using Jscript or .NET in Microsoft Dynamics CRM 2011 With CloseIncidentRequest

This illustration shows how to close a case in Microsoft Dynamics CRM 2011 in code with the CloseIncidentRequest.   This example will be given in Jscript (SOAP) and in C# (.NET).

Ok, here is what the code looks like!
First in C#:

Entity caseResolution = new Entity("incidentresolution");
caseResolution.Attributes.Add("incidentid", new EntityReference("incident", new Guid("C9B4702B-6EBC-E011-8D99-1CC1DE7955DB")));
caseResolution.Attributes.Add("subject", "Customer was mean so we just closed it.");

//service.Create(caseResolution);

CloseIncidentRequest req = new CloseIncidentRequest();
req.IncidentResolution = caseResolution;
req.RequestName = "CloseIncident";
OptionSetValue o = new OptionSetValue();
o.Value = 5;
req.Status = o;

CloseIncidentResponse resp = (CloseIncidentResponse)service.Execute(req);

If you need help instantiating a service object in .NET within a plugin check out this post:
http://mileyja.blogspot.com/2011/04/instantiating-service-object-within.html

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

Now in Jscript


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

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;
               }, 
           CloseIncidentRequest: 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=\"b:CloseIncidentRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
               requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <c:key>IncidentResolution</c:key>";
               requestMain += "            <c:value i:type=\"a:Entity\">";
               requestMain += "              <a:Attributes>";
               requestMain += "                <a:KeyValuePairOfstringanyType>";
               requestMain += "                  <c:key>incidentid</c:key>";
               requestMain += "                  <c:value i:type=\"a:EntityReference\">";
               requestMain += "                    <a:Id>c9b4702b-6ebc-e011-8d99-1cc1de7955db</a:Id>";
               requestMain += "                    <a:LogicalName>incident</a:LogicalName>";
               requestMain += "                    <a:Name i:nil=\"true\" />";
               requestMain += "                  </c:value>";
               requestMain += "                </a:KeyValuePairOfstringanyType>";
               requestMain += "                <a:KeyValuePairOfstringanyType>";
               requestMain += "                  <c:key>subject</c:key>";
               requestMain += "                  <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">Parent Case has been resolved</c:value>";
               requestMain += "                </a:KeyValuePairOfstringanyType>";
               requestMain += "              </a:Attributes>";
               requestMain += "              <a:EntityState i:nil=\"true\" />";
               requestMain += "              <a:FormattedValues />";
               requestMain += "              <a:Id>00000000-0000-0000-0000-000000000000</a:Id>";
               requestMain += "              <a:LogicalName>incidentresolution</a:LogicalName>";
               requestMain += "              <a:RelatedEntities />";
               requestMain += "            </c:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <c:key>Status</c:key>";
               requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
               requestMain += "              <a:Value>5</a:Value>";
               requestMain += "            </c:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "        </a:Parameters>";
               requestMain += "        <a:RequestId i:nil=\"true\" />";
               requestMain += "        <a:RequestName>CloseIncident</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.CloseIncidentResponse(req, successCallback, errorCallback); };
               req.send(requestMain);
           },
       CloseIncidentResponse: 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
};




To understand how to parse the response please review my post on using the DOM parser.
Now you can call the SDK.SAMPLES.CloseIncidentRequest function from your form jscript handler.
Thats all there is to it!

I hope this helps!

11 comments:

  1. Hi Jamie,
    First, thanks by your contribution to Dynamics CRM.
    Do you know if it's possible do the same with OData??

    ReplyDelete
  2. I am not aware of it having ability beyond your basic CRUD functions. For most things requiring the specialized messages in the SDK you may be forced to use SOAP.

    ReplyDelete
  3. Thanks for your quick reply.
    I supposed that you say me, but I wasn't sure at first.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Thank you for your help.

    I had a question: In the incident resolution window there are more data like TimeSpent, Description,

    Did you have any idea about how to add them in the JavaScript CloseIncidentRequest ?

    ReplyDelete
  6. You see this in integration and migration too. The UI automatically creates an OpportunityClose record and attaches it. You also need to create an opportunityclose record and attach it separately to get the same functionality. The opportunityclose entity tracks the data points you are looking for.

    ReplyDelete
  7. Hi, Jamie - I hope you are still willing to answer inquiries regarding this post!

    I have implemented this on a development machine (VM - hosted on my dev box) and it worked great! Then I applied the unmanaged solution to our test machine (VM - hosted on an ESXi server) and it fails (I see in CloseIncidentResponse() that the readyState == 4 and status == 0).

    Other "data points":
    1. Dev system succeeds no matter where the client is located.
    2. Test system succeeds if client is on the test vm.
    3. Test system fails if the client is on any other machine.
    4. I have tried to implement CORS on the Test system (and modified the CloseIncidentResponse ()javascript accordingly) and it still fails:
    a. my uploadTransferFailed() fires with an uninformative error.
    b. I see no relevant http errors on the server.
    5. Dev system started as a clone of the Test vm.
    6. Both Dev and Test: Win Server 2008 R2, CRM 2011, SQL 2008 R2.

    Any ideas? Thoughts on logging/tracing that might reveal the problem on the Test VM?

    Thanks!

    ReplyDelete
  8. Also: Active Directory, of course.

    ReplyDelete
  9. The fact that there are no http errors on the server and that the error is caught on the client in the upload error listener suggests to me that the problem is on the client. However, I can use the same client to hit my Dev CRM system and it works fine.

    ReplyDelete
  10. Other processes on the Test CRM system work fine, too. I can create, edit, cancel, etc. an Incident without error.

    ReplyDelete