Tuesday, 21 October 2014

The Sdk.Soap.js – code samples of Sdk.Sync namespace

 

This post is related to my previous post. So, I suggest to read that first using the following link, in case you did not read it yet.

http://ankit.inkeysolutions.com/2014/10/sdksoapjs.html

In this post I’m sharing the sample code for the most common messages of the Sdk.Sync namespace.

Examples:

· Create

function SyncCreateRecord() {
  var contact = new Sdk.Entity("contact");
  var userID = new Sdk.EntityReference("systemuser", "GUID"); //Use the GUID value of user record
  contact.addAttribute(new Sdk.String("lastname", "Sync record Last Name"));
  contact.addAttribute(new Sdk.Lookup("ownerid", userID));
  var createdRecordID = Sdk.Sync.create(contact);
  alert("Contact created successfully : \"" + createdRecordID + "\"");
}

· Update



function SyncUpdateRecord() {
  var contact = new Sdk.Entity("contact");
  contact.addAttribute(new Sdk.Guid("contactid", "GUID")); //Use the GUID value of contact record
  contact.addAttribute(new Sdk.String("lastname", "Sync record Last Name Updated"));
  var result = Sdk.Sync.update(contact);
  if (result == true) {
    alert("Contact updated successfully.");
  }
  else {
    alert("Contact not updated.");
  }
}
· Delete

function SyncDeleteRecord() {
  //Use the GUID value of contact record
  Sdk.Sync.del("contact", "GUID"); 
  alert("Contact deleted successfully.");
}

· Retrieve



function SyncReteriveRecord() {
  var columnSet = new Sdk.ColumnSet();
  columnSet.addColumn("fullname");
  //Use the GUID value of contact record
  var contact = Sdk.Sync.retrieve("contact", "GUID", columnSet);
  alert("Retrieved contact : \"" + contact.getValue("fullname") + "\"");
}

· RetrieveMultiple



o QueryByAttribute



function SyncRetrieveMultipleByQueryByAttribute() {
  var fetchQuery = new Sdk.Query.QueryByAttribute("contact");
  fetchQuery.setColumnSet("fullname");
  fetchQuery.addAttributeValue(new Sdk.String("middlename", "middle"));
  var result = Sdk.Sync.retrieveMultiple(fetchQuery);
  MethodToBePassedTheResults(result);
}


o QueryExpression



function SyncRetrieveMultipleByQueryExpression() {
  var fetchQuery = new Sdk.Query.QueryExpression("contact");
  fetchQuery.addColumn("fullname");
  var middleName = "middle";
  var values = new Sdk.Query.Strings([middleName]);
  fetchQuery.addCondition("contact", "middlename", Sdk.Query.ConditionOperator.Equal, values);
  var result = Sdk.Sync.retrieveMultiple(fetchQuery);
  MethodToBePassedTheResults(result);
}


o FetchExpression



function SyncRetrieveMultipleByFetchXML() {
  var fetchXml = ["<fetch version=\"1.0\" output-format=\"xml-platform\" mapping=\"logical\" distinct=\"false\">",
                    "<entity name=\"contact\"> ",
                    "  <attribute name=\"fullname\" /> ",
                    "  <order attribute=\"fullname\" descending=\"false\" /> ",
                    "  <filter type=\"and\"> ",
                    "    <condition attribute=\"middlename\" operator=\"eq\" value=\"middle\" /> ",
                    "  </filter> ",
                    " </entity> ",
                    " </fetch>"].join("");
  var fetchQuery = new Sdk.Query.FetchExpression(fetchXml);
  var result = Sdk.Sync.retrieveMultiple(fetchQuery);
  MethodToBePassedTheResults(result);


o MethodToBePassedTheResults, a common method which is being used in above RetrieveMultiple options.



function MethodToBePassedTheResults(cb) {
   if (cb.getEntities().getCount() >= 1) {
    alert(cb.getEntities().getCount());
  }
  else {
    alert("No result");
  }
}

· Associate


For this message, I’ve created custom many-to-many relationship between account and contact i.e. new_contact_account.



function SyncAssociateRecord() {
//Use the GUID value of account record
  var account = new Sdk.EntityReference("account", "GUID");
  var collection = new Sdk.Collection(Sdk.EntityReference, new Array(account));
  //Use the GUID value of contact record
  Sdk.Sync.associate("contact", "GUID", "new_contact_account", collection);
  alert("Contact - Account Associated");
 
}

· Disassociate

For this message, I’ve created custom many-to-many relationship between account and contact i.e. new_contact_account.

function SyncDisassociateRecord() {
  //Use the GUID value of account record
  var account = new Sdk.EntityReference("account", "GUID");
  var collection = new Sdk.Collection(Sdk.EntityReference, new Array(account));
  //Use the GUID value of contact record
  Sdk.Sync.disassociate("contact", "GUID", "new_contact_account", collection);
  alert("Contact - Account Disassociated");
 
}

· SetState

This message is not included in common messages file i.e. Sdk.Soap.vsdoc.js. They provided a separate file, the Sdk.SetState.vsdoc.js to incorporate this message. To use this file we need to slightly change the existing code. We need to add the following line as the first line of the Sdk.SetState.vsdoc.js file,

Sdk = window.Sdk || { __namespace: true };

And we need to include two files at entity form load event:

Sdk.Soap.vsdoc.js

Sdk.SetState.vsdoc.js

Now, we are all set to use the following method.



function jQuerySetStateActivateRecord() {
  //Use the GUID value of contact record
  var contactMoniker = new Sdk.EntityReference("contact", "GUID");
  var setStateRequest = new Sdk.SetStateRequest(contactMoniker, 0, 1); 
  //To deactivate record, use same code just pass state = 1 and status = 2) at above line
  Sdk.Sync.execute(setStateRequest);
  alert("Contcat Activated.");
}

I hope this would be helpful. In my upcoming post, I will be covering the sample code for Sdk.JQ and Sdk.Q namespaces.


Thanks for reading this far.

Friday, 3 October 2014

Sdk.Soap.js

 

In this post, I would like to share details about the Sdk.Soap.js library and sample code for some of the very commonly used messages. At present this library supports 202 messages. It helps in writing easy and quick SOAP call(s) in web resources and reduces the size of the source code a lot. Also, these SOAP call(s) are easy in understanding and reading. In Dynamics CRM, we can write both REST and SOAP calls. However, The REST calls have its’ own limitations. Please refer following URL to know more about oData endpoint limitations.

http://ankit.inkeysolutions.com/2012/03/limitations-of-odata-endpoint-in-crm.html

To overcome these problems it is good to use quick SOAP calls with the help of the Sdk.Soap.js

Note: This library does not provide code to authenticate.

The Sdk.soap.js library comprises of 4 types of namespaces:

1. Sdk.Async

2. Sdk.Sync

3. Sdk.jQ

4. Sdk.Q

The first two namespaces can be used directly at form events like form load, form save, attribute on change etc. Their names itself help us to realise which namespace needs to be used for asynchronous operation(s) and synchronous operation(s). The last two should be used in HTML web resources. Additionally, you can reduce the size of this library by removing the unrequired namespaces from the Sdk.Soap.vsdoc.js file.

In this blog I would like to cover the sample code for the most common messages of the first namespace i.e. Sdk.Async

Examples:

· Create

function AsyncCreateRecord() {
  var contact = new Sdk.Entity("contact");
  var userID = new Sdk.EntityReference("systemuser", "GUID ");  //Use the GUID value of user record
  contact.addAttribute(new Sdk.String("lastname", "Async record Last Name"));
  contact.addAttribute(new Sdk.Lookup("ownerid", userID));
  Sdk.Async.create(contact, function (newlyCreatedRecordID) { alert("Async Contact created successfully : \"" + newlyCreatedRecordID  + "\""); });
}

· Update



function AsyncUpdateRecord() {
  var contact = new Sdk.Entity("contact");
  contact.addAttribute(new Sdk.Guid("contactid", "GUID ");  //Use the GUID value of user record
  contact.addAttribute(new Sdk.String("lastname", "Async record Last Name Updated"));
  Sdk.Async.update(contact, function () {
    alert("Contact updated successfully.");
  });
}

· Delete



function AsyncDeleteRecord() {
 //Use the GUID value of contact record
  Sdk.Async.del("contact", "GUID", function () {
    alert("Contact deleted successfully.");
  });
}

· Retrieve



function AsyncReteriveRecord() {
  var columnSet = new Sdk.ColumnSet();
  columnSet.addColumn("fullname");
 //Use the GUID value of contact record
  Sdk.Async.retrieve("contact", "GUID", columnSet, function (contact) {
    alert("Retrieved contact : \"" + contact.getValue("fullname") + "\"");
  });
}

· RetrieveMultiple



o QueryByAttribute



function AsyncRetrieveMultipleByQueryByAttribute () {
  var fetchQuery = new Sdk.Query.QueryByAttribute("contact");
  fetchQuery.setColumnSet("fullname");
  fetchQuery.addAttributeValue(new Sdk.String("middlename", "middle"));
  Sdk.Async.retrieveMultiple(fetchQuery, RetrieveMultipleCallBack);
}


o QueryExpression



function AsyncRetrieveMultipleByQueryExpression () {
  var fetchQuery = new Sdk.Query.QueryExpression("contact");
  fetchQuery.addColumn("fullname");
  var middleName = "middle";
  var values = new Sdk.Query.Strings([middleName]);
  fetchQuery.addCondition("contact", "middlename", Sdk.Query.ConditionOperator.Equal, values);
  Sdk.Async.retrieveMultiple(fetchQuery, RetrieveMultipleCallBack);
}

o FetchExpression




function AsyncRetrieveMultipleByFetchXML () {
  var fetchXml = ["<fetch version=\"1.0\" output-format=\"xml-platform\" mapping=\"logical\" distinct=\"false\">",
                    "<entity name=\"contact\"> ",
                    "  <attribute name=\"fullname\" /> ",
                    "  <order attribute=\"fullname\" descending=\"false\" /> ",
                    "  <filter type=\"and\"> ",
                    "    <condition attribute=\"middlename\" operator=\"eq\" value=\"middle\" /> ",
                    "  </filter> ",
                    " </entity> ",
                    " </fetch>"].join("");
  var fetchQuery = new Sdk.Query.FetchExpression(fetchXml);
  Sdk.Async.retrieveMultiple(fetchQuery, RetrieveMultipleCallBack);
}

· Associate

For this message, I’ve created custom many-to-many relationship between account and contact i.e. new_contact_account



function AsyncAssociateRecord() {
  //Use the GUID value of account record
  var account = new Sdk.EntityReference("account", "GUID");
  var collection = new Sdk.Collection(Sdk.EntityReference, new Array(account));
  //Use the GUID value of contact record
  Sdk.Async.associate("contact", "GUID", "new_contact_account", collection);
  alert("Contact - Account Associated");
}

· Disassociate

For this message, I’ve created custom many-to-many relationship between account and contact i.e. new_contact_account



function AsyncDisassociateRecord() {
  //Use the GUID value of account record
  var account = new Sdk.EntityReference("account", "GUID");
  var collection = new Sdk.Collection(Sdk.EntityReference, new Array(account));
  //Use the GUID value of contact record
  Sdk.Async.disassociate("contact", "GUID", "new_contact_account", collection);
  alert("Contact - Account Disassociated");
}

· SetState

This message is not included in common messages file i.e. Sdk.Soap.vsdoc.js. They provided a separate file, the Sdk.SetState.vsdoc.js to incorporate this message. To use this file we need to slightly change the existing code. We need to add the following line as the first line of the Sdk.SetState.vsdoc.js file,

Sdk = window.Sdk || { __namespace: true };

And we need to include two files at entity form load event:

Sdk.Soap.vsdoc.js

Sdk.SetState.vsdoc.js

Now, we are all set to use the following method.



function jQuerySetStateActivateRecord() {
//Use the GUID value of contact record
  var contactMoniker = new Sdk.EntityReference("contact", "GUID");
  var setStateRequest = new Sdk.SetStateRequest(contactMoniker, 0, 1); 
  //To deactivate record, use same code just pass state = 1 and status = 2) at above line
  Sdk.Async.execute(setStateRequest, function () { alert("Contcat Activated."); });
}

Note: If you do not want to change the Sdk.soap.vsdoc.js file by removing unrequired namespaces then I recommend to use the minified version of the same file i.e. Sdk.soap.min.js. This file is also bundled in this library.

For more details, please refer the following links:

http://code.msdn.microsoft.com/SdkSoapjs-9b51b99a

http://code.msdn.microsoft.com/SdkSoapjs-Samples-378151cd

I would be covering the sample code of other 3 namespaces in my upcoming posts.

I hope this would be helpful.

 




The simplest and quickest way to insert data for Many-to-Many relationship in Dynamics CRM is the Drag and drop listbox.

http://www.inkeysolutions.com/DynamicCRMDragAndDropListBox.html

Wednesday, 1 October 2014

The one and only Drag and Drop listbox

Hello Everyone,

I hope you do well today.
 
We are pleased to share following updates related to the “Drag and Drop listbox” add-on.

       1.       It is upgraded to CRM 2013 now.

2.       It uses HTML5 technology instead of Silverlight 5.0.

3.       It can be accessed in tablet devices too.

4.       It can be configured on multiple forms of an entity.

5.       It now stores the data into many-to-many relationship instead of coma separated value as an attribute of an entity.

Additionally, the organisation level license is now available only @ 125 USD. 

So, download the trial version using the below URL and take the benefits of all above features of one and only, the “Drag and Drop listbox” .


Thanks.

Friday, 25 July 2014

Dynamics CRM 2013 / 2011 - On custom ribbon button click, create a new record, and open this newly created record

 

I’m feeling really happy while writing this blog, because it’s over a year that I got a chance to write it. I have been too busy for last year to write even a single blog. From now on, I’m hoping to keep this activity continued.

In this blog I would like to explain how to create a new record and open the same on click of custom ribbon button in Dynamics CRM. The steps are as following:

1. Create a custom ribbon button on a specific entity, the source entity. Use the Ribbon Workbench tool to add a button on this entity. This tool can be downloaded using following link.

http://www.develop1.net/public/page/Ribbon-Workbench-for-Dynamics-CRM-2011.aspx

2. Create a custom attribute of type of “Two Options” on the source entity say new_isribbonbuttonclicked. (specified above in step 1).

This field helps us in plug-in to identify whether the ribbon button is clicked by a user or not.

When the user clicks on this newly added button, a new record gets created via plug-in and the same will be opened in a new window with CRM 2011 or in a same window in CRM 2013.

3. Create another attribute of type “Single line text” on the same entity say new_uniqueidentifierofentity. This attribute will hold the GUID value of a newly created record.

The value of this field will be used in JavaScript/web resource code to open the newly created

record.

Create a new web resource of type Script (JScript) and write the following JavaScript code in it. This code updates the value as “True” to the new_isribbonbuttonclicked attribute.

   1: //Change the method and attribute name as per your need
   2: function UpdateAttribute() {
   3:   var attribute = Xrm.Page.getAttribute("new_isribbonbuttonclicked"); //Specify the name of your attribute
   4:   var attributeValue = null;
   5:   if (attribute != null) {
   6:     attributeValue = attribute.getValue();
   7:     if (attributeValue == null ||
   8:         attributeValue == false) {
   9:       attribute.setValue(true);
  10:       attribute.setSubmitMode("always");
  11:       Xrm.Page.data.entity.save();
  12:     }
  13:   }
  14: }


5. Call the above JavaScript function from the ribbon button which we have created at very first step of this post.

6. Now, write a pre update plug-in on the source entity. In this plug-in just check whether the plug-in context contains the new_isribbonbuttonclicked attribute or not. If it exists in the context and the value of this attribute is “True” then create a record of another entity and get the unique identifier (GUID) of the newly created record from the response of the SDK call.

7. Then, add this GUID to the plug-in context for the new_uniqueidentifierofentity field.

Like,

entity.Attributes[new_uniqueidentifierofentity] = GUID; //Specify the name of your attribute

8. Also add the new_isribbonbuttonclicked field in the plug-in context as “False”. So that, the custom ribbon button will work for the next attempt.

9. At the end of plug-in execution the above attribute values get automatically updated.

10. Lastly, add another method in the web resource of the source entity and bind this method to “form load” event. Primarily, this method checks following two conditions.

· The form is loaded into the edit mode or not.

· The new_uniqueidentifierofentity attribute contains data or not.

If it satisfies both the conditions, meant if the record is opened in edit mode and the GUID attribute contains unique identifier of newly created record then just write a code to open this record, update the value of new_uniqueidentifierofentity to null, and save the form.

Following is the code that performs the things that we specified here in this step.



   1: //Change the method and attribute name as per your need
   2: function Form_Load() {
   3:   if (Xrm.Page.ui.getFormType() == 2) {
   4:     var attribute = Xrm.Page.getAttribute("AttributeName"); //Specify the name of your attribute
   5:     var attributeValue = null;
   6:     if (attribute != null) {
   7:       attributeValue = attribute.getValue();
   8:       if (attributeValue != null &&
   9:           attributeValue != "") {
  10:         Xrm.Utility.openEntityForm("EntityName", attributeValue);
  11:         attribute.setValue(null);
  12:         attribute.setSubmitMode("always");
  13:         Xrm.Page.data.entity.save();
  14:       }
  15:     }
  16:   }
  17: }

That’s it!

Hope, this helps. Thanks.

Saturday, 29 June 2013

Dynamics CRM 2011 On-premises - Use “Execute AS” to call custom stored procedures

For one of our customers, we had created some custom stored procedures in a separate database with CRM plugins to replace their existing SQL triggers. We required these SPs “as is” because they were having very complex logic inside them and would have taken ample amount of time to re-write the complete logic in CRM plugins. Hence, We had just reused those objects and amended it to make them compliance with Dynamics CRM standards by fetching the data from filtered views instead of direct table hits. Like,

Select * from DBO. Account

was replaced with,

Select {required columns } from OrganisationName_MSCRM.dbo.FilteredAccount

Inside the Dynamics CRM plugins, we had written the code to connect to the custom database (using windows authentication connection string) and called the above stored procedures. However, surprisingly, the stored procedures did not return any data. Hence, one of our developers came to me with this problem. I knew that the problem is with Application Pool Identity. The CRM plugins are executing under the CRM Application Pool Identity user and that user does not have permission to access the CRM data.

image

The CRM filtered views run under the user security roles and do not return data if you don’t have configured the required privileges. Additionally, we must not configure the Dynamics CRM user as CRM application pool identity. Please refer below URL to know more about Security considerations for Microsoft Dynamics CRM 2011.

http://technet.microsoft.com/en-us/library/hh699825.aspx

Then, I suggested her to add the above application pool identity user to PrivUserGroup. (One of the auto-generated Active Directory groups.) But, in our case the identity pool user was already added in this group. To give complete CRM database access, it can also be added to SQLAccessGroup, however, the situation was same, and the identity was already added here too.

Eventually, we switched to user impersonation. There were two options; either we impersonate the user inside the plugin or at SQL server level. I had asked her to implement the latter one and she tried with “Execute AS” inside the stored procedure and it worked as per the expectation. Below is our complete solution.

1.  Add a new user in SQL server security logins, the security logins area is displayed in below screen shot.

image

OR

If you wish then you can use one of the existing users. However, this user must require sysadmin sever role to execute “Execute AS” command. Below link will help you to get more details on “Execute AS” (transact-SQL).

http://msdn.microsoft.com/en-us/library/ms181362.aspx

2. Use the above SQL user in your connection string to connect with custom database inside CRM plugins, as described below.

Data Source=myServer;Initial Catalog=myDataBase;User Id=myUsername; Password=myPassword;Integrated Security=false

3. Retrieve the domain name of logged in CRM user.

In plugin context you will always get the UserID via Context.UserID property, which is the GUID of the logged in CRM User. Use this value to retrieve the domain name of logged in CRM user from “systemuser” table. Keep this web service call in a common class/method inside your plugin solution, so that, the same can be reused in other plugin classes as well.

4. Pass the above domain name to your custom stored procedure as parameter which can be further used in “Execute AS” command, as shown in below stored procedure.

USE [DBName]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[TestProcedure] 
    @UserName NVARCHAR(100)
AS
BEGIN
    BEGIN TRY
        EXECUTE AS LOGIN =  @UserName 
        SELECT * FROM CRM_DB_Name.dbo.FilteredAccount
        REVERT;
    END TRY
    BEGIN CATCH
        REVERT;
    END CATCH
END

Note: Make sure you write the “REVERT” command to stop the user impersonation inside your stored procedure.

In this way we have impersonated the application pool identity user with the logged in CRM user. Thus, we can fetch the data from filtered views based on logged in user security roles.

I hope this would be helpful.