I have periodically ran into the following exception on my CRM 2011 virtual dev machine:
System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail. ---> System.ServiceModel.FaultException: An error occurred when verifying security for the message.
I have found ways to work around this now every time I have ran into it.
I have noticed another Exception with the same cause before when working with the CrmSvcUtil.exe tool.
Cause: Timezone or time being wrong on the client or server.
Resolution: Correct date and time settings on affected machine, also restart client application making call
Example Post Illustrating: http://social.msdn.microsoft.com/Forums/is/wcf/thread/d7a13c9b-2144-4b0d-9585-5a487126ab1f
I had to restart Visual Studio on the client machine after I fixed the time on the server for my calls to function properly.
I hope this helps!
Monday, March 21, 2011
Wednesday, March 16, 2011
RetrieveMultiple Calls in Jscript in Microsoft Dynamics CRM 2011
RetrieveMultiple is probably the most common call you will have to format up in your Microsoft CRM career, It has been for me anyways. I wanted to give you a couple examples of how to do this in Jscript. The first one is taken partially derived from the SDK that contains a linkentity (join) and the second is a simpler call that is a basic call that has criteria (where clause) but no links (joins).
This example is asynchronous, if you want to learn how to make JScript SOAP calls synchronously please visit this post: http://mileyja.blogspot.com/2011/07/using-jscript-to-access-soap-web.html
These examples were formatted up using the soaplogger solution included in the SDK in conjunction with the CRM 2011 SOAP Request Formatter. The project for the formatter is at http://crm2011soap.codeplex.com/
To learn the ins and outs of parsing the response in 2011 using the DOM parser review this post.
http://mileyja.blogspot.com/2011/03/microsoft-dynamics-crm-2011-parsing.html
You can call either of these examples using the following in the GUI form eventhandler interface:
SDK.SAMPLES.RetrieveMultipleRequest
Call #1: returns (alerts) the name of the roles for a user when a valid guid is provided. (you will have to replace the guid with a valid one from your system) To do this see the systemuserbase table in your org database
Call #2: returns (alerts) the name of an account when a valid guid is provided. (you will have to replace the guid with a valid one from your system) To do this see the accountbase table in your org database. One other thing is that if you queried by a different attribute besides id you could get more than one record which is usually the point of a retrievemultiple.
I hope this helps!!
This example is asynchronous, if you want to learn how to make JScript SOAP calls synchronously please visit this post: http://mileyja.blogspot.com/2011/07/using-jscript-to-access-soap-web.html
These examples were formatted up using the soaplogger solution included in the SDK in conjunction with the CRM 2011 SOAP Request Formatter. The project for the formatter is at http://crm2011soap.codeplex.com/
To learn the ins and outs of parsing the response in 2011 using the DOM parser review this post.
http://mileyja.blogspot.com/2011/03/microsoft-dynamics-crm-2011-parsing.html
You can call either of these examples using the following in the GUI form eventhandler interface:
SDK.SAMPLES.RetrieveMultipleRequest
Call #1: returns (alerts) the name of the roles for a user when a valid guid is provided. (you will have to replace the guid with a valid one from your system) To do this see the systemuserbase table in your org database
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;
},
RetrieveMultipleRequest: 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:RetrieveMultipleRequest\" 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>Query</b:key>";
requestMain += " <b:value i:type=\"a:QueryExpression\">";
requestMain += " <a:ColumnSet>";
requestMain += " <a:AllColumns>false</a:AllColumns>";
requestMain += " <a:Columns xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">";
requestMain += " <c:string>name</c:string>";
requestMain += " </a:Columns>";
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>role</a:EntityName>";
requestMain += " <a:LinkEntities>";
requestMain += " <a:LinkEntity>";
requestMain += " <a:Columns>";
requestMain += " <a:AllColumns>false</a:AllColumns>";
requestMain += " <a:Columns xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />";
requestMain += " </a:Columns>";
requestMain += " <a:EntityAlias i:nil=\"true\" />";
requestMain += " <a:JoinOperator>Inner</a:JoinOperator>";
requestMain += " <a:LinkCriteria>";
requestMain += " <a:Conditions>";
requestMain += " <a:ConditionExpression>";
requestMain += " <a:AttributeName>systemuserid</a:AttributeName>";
requestMain += " <a:Operator>Equal</a:Operator>";
requestMain += " <a:Values xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">";
requestMain += " <c:anyType i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">81ED14D9-4441-E011-963A-080027AD5B6E</c:anyType>";
requestMain += " </a:Values>";
requestMain += " </a:ConditionExpression>";
requestMain += " </a:Conditions>";
requestMain += " <a:FilterOperator>And</a:FilterOperator>";
requestMain += " <a:Filters />";
requestMain += " </a:LinkCriteria>";
requestMain += " <a:LinkEntities />";
requestMain += " <a:LinkFromAttributeName>roleid</a:LinkFromAttributeName>";
requestMain += " <a:LinkFromEntityName>role</a:LinkFromEntityName>";
requestMain += " <a:LinkToAttributeName>roleid</a:LinkToAttributeName>";
requestMain += " <a:LinkToEntityName>systemuserroles</a:LinkToEntityName>";
requestMain += " </a:LinkEntity>";
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:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>RetrieveMultiple</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.RetrieveMultipleResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
RetrieveMultipleResponse: 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)
//***********************
// 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
};
Call #2: returns (alerts) the name of an account when a valid guid is provided. (you will have to replace the guid with a valid one from your system) To do this see the accountbase table in your org database. One other thing is that if you queried by a different attribute besides id you could get more than one record which is usually the point of a retrievemultiple.
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;
},
RetrieveMultipleRequest: 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:RetrieveMultipleRequest\" 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>Query</b:key>";
requestMain += " <b:value i:type=\"a:QueryExpression\">";
requestMain += " <a:ColumnSet>";
requestMain += " <a:AllColumns>false</a:AllColumns>";
requestMain += " <a:Columns xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">";
requestMain += " <c:string>name</c:string>";
requestMain += " </a:Columns>";
requestMain += " </a:ColumnSet>";
requestMain += " <a:Criteria>";
requestMain += " <a:Conditions>";
requestMain += " <a:ConditionExpression>";
requestMain += " <a:AttributeName>accountid</a:AttributeName>";
requestMain += " <a:Operator>Equal</a:Operator>";
requestMain += " <a:Values xmlns:c=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">";
requestMain += " <c:anyType i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">ABA9D2CE-CD4B-E011-9078-080027AD5B6E</c:anyType>";
requestMain += " </a:Values>";
requestMain += " </a:ConditionExpression>";
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:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>RetrieveMultiple</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.RetrieveMultipleResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
RetrieveMultipleResponse: 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)
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
};
I hope this helps!!
Labels:
CRM 2011,
CRM Online,
jscript,
Microsoft Dynamics CRM
Tuesday, March 15, 2011
CRM 2011 Jscript Soap Request Formatter RELEASED!!
I know some of you have seen the crazy Jscript libraries I have been putting up here recently. What if you could take the XML from a captured request and create one of those things instantaniously? Well, now you can with my CRM 2011 Jscript SOAP Request Formatter, hosted on CodePlex, it takes much of the tediousness out of formatting straight XML for Jscript SOAP calls within CRM 2011.
Link to CodePlex project: http://crm2011soap.codeplex.com/
How Do You Use It.
It would be nice to just use fiddler for viewing traffic, but if you view the traffic on the new organization service endpoint you can't see any of the traffic as it is encrypted
In the SDK, if you go to /SDK/helpercode/cs/client, there is a soaplogger solution included that allows you to capture decrypted SOAP envelope requests and responses that you send to and from the CRM 2011 SOAP Endpoint.
There is a tutorial on creating interactive web resource libraries from the soaplogger captured requests here:
http://msdn.microsoft.com/en-us/library/gg594434.aspx
When you finish with the soaplogger you get an output text that contains a request envelope in the "HTTP REQUEST" section of the document that might look like this:
Ok, you can open the .exe file contained in the /bin/debug folder from the downloaded release now.
Now if you hit generate it will tranform the insert XML into the JScript call that is ready to be imported in CRM as a Web Resource and utilized on your forms. This is what it will look like using our example.
You can now parse in your form fields or values as needed and you can call the function in the eventhandler setup by using the syntax SDK.{namespace}.{function name}Request, or in our case:
SDK.EXAMPLE.InsertOptionValueRequest
I hope this helps!
Link to CodePlex project: http://crm2011soap.codeplex.com/
How Do You Use It.
It would be nice to just use fiddler for viewing traffic, but if you view the traffic on the new organization service endpoint you can't see any of the traffic as it is encrypted
In the SDK, if you go to /SDK/helpercode/cs/client, there is a soaplogger solution included that allows you to capture decrypted SOAP envelope requests and responses that you send to and from the CRM 2011 SOAP Endpoint.
There is a tutorial on creating interactive web resource libraries from the soaplogger captured requests here:
http://msdn.microsoft.com/en-us/library/gg594434.aspx
When you finish with the soaplogger you get an output text that contains a request envelope in the "HTTP REQUEST" section of the document that might look like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<request i:type="a:InsertOptionValueRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">
<a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<a:KeyValuePairOfstringanyType>
<b:key>Label</b:key>
<b:value i:type="a:Label">
<a:LocalizedLabels>
<a:LocalizedLabel>
<a:IsManaged i:nil="true" />
<a:Label>testoptionCode9</a:Label>
<a:LanguageCode>1033</a:LanguageCode>
</a:LocalizedLabel>
</a:LocalizedLabels>
<a:UserLocalizedLabel i:nil="true" />
</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>AttributeLogicalName</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema%22%3Enew_testoptionset%3C/b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>EntityLogicalName</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema%22%3Eaccount%3C/b:value>
</a:KeyValuePairOfstringanyType>
</a:Parameters>
<a:RequestId i:nil="true" />
<a:RequestName>InsertOptionValue</a:RequestName>
</request>
</Execute>
</s:Body>
</s:Envelope>
Ok, you can open the .exe file contained in the /bin/debug folder from the downloaded release now.
Next, if you copy this envelope into the Soap Formatter UI (right now you have to do all copy and past and select-all operations using right click on the textbox in the Soap Formatter UI :( I am sure this will be fixed at some later point) and type in a namespace (we will use "EXAMPLE") and a function name (we will use "InsertOptionValue"). It should look like this.
Now if you hit generate it will tranform the insert XML into the JScript call that is ready to be imported in CRM as a Web Resource and utilized on your forms. This is what it will look like using our example.
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.EXAMPLE = {
_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;
},
InsertOptionValueRequest: 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:InsertOptionValueRequest\" 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>Label</b:key>";
requestMain += " <b:value i:type=\"a:Label\">";
requestMain += " <a:LocalizedLabels>";
requestMain += " <a:LocalizedLabel>";
requestMain += " <a:IsManaged i:nil=\"true\" />";
requestMain += " <a:Label>testoptionCode9</a:Label>";
requestMain += " <a:LanguageCode>1033</a:LanguageCode>";
requestMain += " </a:LocalizedLabel>";
requestMain += " </a:LocalizedLabels>";
requestMain += " <a:UserLocalizedLabel i:nil=\"true\" />";
requestMain += " </b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>AttributeLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">new_testoptionset</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>EntityLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">account</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>InsertOptionValue</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.EXAMPLE._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.EXAMPLE.InsertOptionValueResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
InsertOptionValueResponse: 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.EXAMPLE._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
};
You can now parse in your form fields or values as needed and you can call the function in the eventhandler setup by using the syntax SDK.{namespace}.{function name}Request, or in our case:
SDK.EXAMPLE.InsertOptionValueRequest
I hope this helps!
I also would love to have a few volunteers help me build the thing out further.
Monday, March 14, 2011
Inserting, Updating, or Deleting OptionSet Values in Microsoft Dynamics CRM 2011 in Jscript
I found the other day how useful it can potentially be to be able to work with optionset values from Jscript in the CRM GUI. I wanted to share quick library I created that inserts, updates, or deletes optionset values in Jscript using the organization service SOAP endpoint from within the application.
(Note: The code looks better once you copy and paste it to a different location.)
You will want to remove anything you don't way from the library, and you will also want to parse in your own values for the edits as the functions currently assume static values that I used for my test scenarios.
You can then call these functions using the following syntax when hooking up the eventhandlers in CRM:
SDK.OPTIONSETVALUE.InsertOptionValueRequest
SDK.OPTIONSETVALUE.UpdateOptionValueRequest
SDK.OPTIONSETVALUE.DeleteOptionValueRequest
If you are working with optionsets this way you may also want to review my blogpost on how to publish entities from Jscript so you can immediately work with your changes you make with this library at http://mileyja.blogspot.com/2011/03/publish-entity-in-jscript-in-crm-2011.html
I hope this helps, and Enjoy!!
(Note: The code looks better once you copy and paste it to a different location.)
You will want to remove anything you don't way from the library, and you will also want to parse in your own values for the edits as the functions currently assume static values that I used for my test scenarios.
You can then call these functions using the following syntax when hooking up the eventhandlers in CRM:
SDK.OPTIONSETVALUE.InsertOptionValueRequest
SDK.OPTIONSETVALUE.UpdateOptionValueRequest
SDK.OPTIONSETVALUE.DeleteOptionValueRequest
If you are working with optionsets this way you may also want to review my blogpost on how to publish entities from Jscript so you can immediately work with your changes you make with this library at http://mileyja.blogspot.com/2011/03/publish-entity-in-jscript-in-crm-2011.html
I hope this helps, and Enjoy!!
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.OPTIONSETVALUE = {
_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;
},
InsertOptionValueRequest: 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:InsertOptionValueRequest\" 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>Label</b:key>";
requestMain += " <b:value i:type=\"a:Label\">";
requestMain += " <a:LocalizedLabels>";
requestMain += " <a:LocalizedLabel>";
requestMain += " <a:IsManaged i:nil=\"true\" />";
requestMain += " <a:Label>testoptionCode9</a:Label>";
requestMain += " <a:LanguageCode>1033</a:LanguageCode>";
requestMain += " </a:LocalizedLabel>";
requestMain += " </a:LocalizedLabels>";
requestMain += " <a:UserLocalizedLabel i:nil=\"true\" />";
requestMain += " </b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>AttributeLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">new_testoptionset</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>EntityLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">account</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>InsertOptionValue</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.OPTIONSETVALUE._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.OPTIONSETVALUE.InsertOptionValueResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
InsertOptionValueResponse: 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 successful 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.OPTIONSETVALUE._getError(req.responseXML));
}
}
},
UpdateOptionValueRequest: 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:UpdateOptionValueRequest\" 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>Value</b:key>";
requestMain += " <b:value i:type=\"c:int\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">100000001</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>MergeLabels</b:key>";
requestMain += " <b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">false</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>EntityLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">account</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>AttributeLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">new_testoptionset</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>Label</b:key>";
requestMain += " <b:value i:type=\"a:Label\">";
requestMain += " <a:LocalizedLabels>";
requestMain += " <a:LocalizedLabel>";
requestMain += " <a:IsManaged i:nil=\"true\" />";
requestMain += " <a:Label>Updated Option 1</a:Label>";
requestMain += " <a:LanguageCode>1033</a:LanguageCode>";
requestMain += " </a:LocalizedLabel>";
requestMain += " </a:LocalizedLabels>";
requestMain += " <a:UserLocalizedLabel i:nil=\"true\" />";
requestMain += " </b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>UpdateOptionValue</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.OPTIONSETVALUE._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.OPTIONSETVALUE.UpdateOptionValueResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
UpdateOptionValueResponse: 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.OPTIONSETVALUE._getError(req.responseXML));
}
}
},
DeleteOptionValueRequest: 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:DeleteOptionValueRequest\" 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>Value</b:key>";
requestMain += " <b:value i:type=\"c:int\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">100000001</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>EntityLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">account</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>AttributeLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">new_testoptionset</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>DeleteOptionValue</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.OPTIONSETVALUE._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.OPTIONSETVALUE.DeleteOptionValueResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
DeleteOptionValueResponse: 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.OPTIONSETVALUE._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
};
//************************
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.OPTIONSETVALUE = {
_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;
},
UpdateOptionValueRequest: 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:UpdateOptionValueRequest\" 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>Value</b:key>";
requestMain += " <b:value i:type=\"c:int\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">100000001</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>MergeLabels</b:key>";
requestMain += " <b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">false</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>EntityLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">account</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>AttributeLogicalName</b:key>";
requestMain += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">new_testoptionset</b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <b:key>Label</b:key>";
requestMain += " <b:value i:type=\"a:Label\">";
requestMain += " <a:LocalizedLabels>";
requestMain += " <a:LocalizedLabel>";
requestMain += " <a:IsManaged i:nil=\"true\" />";
requestMain += " <a:Label>Updated Option 1</a:Label>";
requestMain += " <a:LanguageCode>1033</a:LanguageCode>";
requestMain += " </a:LocalizedLabel>";
requestMain += " </a:LocalizedLabels>";
requestMain += " <a:UserLocalizedLabel i:nil=\"true\" />";
requestMain += " </b:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>UpdateOptionValue</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.OPTIONSETVALUE._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.OPTIONSETVALUE.UpdateOptionValueResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
UpdateOptionValueResponse: 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.OPTIONSETVALUE._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
};
//*******************************
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.OPTIONSETVALUE = {
_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;
},
_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
};
Saturday, March 12, 2011
Publish an Entity in Jscript in Microsoft Dynamics CRM 2011
If you work with the metadata messages of the CRM 2011 OrganizationService in Jscript I can see how it would be useful to have the ability to publish an entity in Jscript. So here is how you do it.
The only thing you need to change in the code below is the word account to whatever entity you want to publish in the annotated line. You might also want to do a find/replace on the word account if you change it to a different entity so your code isn't confusing to other people because you are publishing the contact entity with a PublishAccountRequest function.
The function within this library can then by called by adding the following command reference to an eventhandler on a form in CRM.
This example is asynchronous, if you want to learn how to make JScript SOAP calls synchronously please visit this post: http://mileyja.blogspot.com/2011/07/using-jscript-to-access-soap-web.html
SDK.PUBLISH.PublishAccountRequest
When copied from here and pasted elsewhere, the code looks a lot better.
Have a great weekend and check back soon, I have some big surprises coming up in the near future in this series of Jscript CRM 2011 posts.
The only thing you need to change in the code below is the word account to whatever entity you want to publish in the annotated line. You might also want to do a find/replace on the word account if you change it to a different entity so your code isn't confusing to other people because you are publishing the contact entity with a PublishAccountRequest function.
The function within this library can then by called by adding the following command reference to an eventhandler on a form in CRM.
This example is asynchronous, if you want to learn how to make JScript SOAP calls synchronously please visit this post: http://mileyja.blogspot.com/2011/07/using-jscript-to-access-soap-web.html
SDK.PUBLISH.PublishAccountRequest
When copied from here and pasted elsewhere, the code looks a lot better.
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.PUBLISH = {
_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;
},
PublishAccountRequest: 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:PublishXmlRequest\" 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>ParameterXml</c:key>";
// ONE STEP SCRIPT CONFIGURATION: The Line below contains the word "account", you can change this name to whatever entity you want to publish
requestMain += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\"><importexportxml><entities><entity>account</entity></entities></importexportxml></c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>PublishXml</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.PUBLISH._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.PUBLISH.PublishAccountResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
PublishAccountResponse: 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.PUBLISH._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
};
Have a great weekend and check back soon, I have some big surprises coming up in the near future in this series of Jscript CRM 2011 posts.
Friday, March 11, 2011
Formatting Currency in Microsoft Dynamics CRM 2011 or 4.0 in Jscript
Hello everyone, I recently had a really hard time trying to find a good currency formatting function for Jscript that worked with CRM 2011 Jscript standards. I found a few functions that I could use together to do it, I have now just rolled them up into one for you guys.
I hope this helps, and Happy Friday!!!
//Format currency in CRM jscript
//EXAMPLE USAGE
//alert(FormatAsCurrency(10000));
function FormatAsCurrency(amount) {
var i = parseFloat(amount);
if (isNaN(i)) { i = 0.00; }
var minus = '';
if (i < 0) { minus = '-'; }
i = Math.abs(i);
i = parseInt((i + .005) * 100);
i = i / 100;
s = new String(i);
if (s.indexOf('.') < 0) { s += '.00'; }
if (s.indexOf('.') == (s.length - 2)) { s += '0'; }
s = minus + s;
amount = s;
var delimiter = ","; // replace comma if other mark is desired
var a = amount.split('.', 2)
var d = a[1];
var i = parseInt(a[0]);
if (isNaN(i)) { return ''; }
var minus = '';
if (i < 0) { minus = '-'; }
i = Math.abs(i);
var n = new String(i);
var a = [];
while (n.length > 3) {
var nn = n.substr(n.length - 3);
a.unshift(nn);
n = n.substr(0, n.length - 3);
}
if (n.length > 0) { a.unshift(n); }
n = a.join(delimiter);
if (d.length < 1) { amount = n; }
else { amount = n + '.' + d; }
amount = minus + amount;
return "$" + amount;
}
I hope this helps, and Happy Friday!!!
Labels:
CRM,
CRM 2011,
CRM Online,
Microsoft Dynamics CRM. jscript
Monday, March 7, 2011
Reflection on CRM 2011 CrmSvcUtil.exe Issues
I was trying to run the CRM web service proxy tool, CrmSvcUtil.exe, on a new computer today I was unfamiliar with and I had a couple exceptions I had to work through that I wanted to quickly highlight.
Exception 1.
Exiting program with exception: Could not load file or assembly 'Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or
one of its dependencies. The system cannot find the file specified.
Enable tracing and view the trace files for more information.
Resolution:
Install Windows Identity Foundation
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=eb9c345f-e830-40b8-a5fe-ae7a864c4d76&displaylang=en
Exception 2.
Exiting program with exception: An error occurred when verifying security for the message.
Enable tracing and view the trace files for more information.
Resolution:
This WCF error was resolved by verifying the clock on the server and dev machine were both properly set. In this case the server was a new Windows Server machine that had just been stood up and the clock had never been set. I changed the time settings and the problem was fixed.
Cheers, and Happy Monday!
Exception 1.
Exiting program with exception: Could not load file or assembly 'Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or
one of its dependencies. The system cannot find the file specified.
Enable tracing and view the trace files for more information.
Resolution:
Install Windows Identity Foundation
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=eb9c345f-e830-40b8-a5fe-ae7a864c4d76&displaylang=en
Exception 2.
Exiting program with exception: An error occurred when verifying security for the message.
Enable tracing and view the trace files for more information.
Resolution:
This WCF error was resolved by verifying the clock on the server and dev machine were both properly set. In this case the server was a new Windows Server machine that had just been stood up and the clock had never been set. I changed the time settings and the problem was fixed.
Cheers, and Happy Monday!
Subscribe to:
Posts (Atom)
