Sunday, March 18, 2012

Authentication Issue in Outlook Client for CRM 2011 - How to open custom web page from ribbon within Outlook Client for MS Dynamics CRM 2011

Generally, we use Window.Open(url,name,width, height) to open a custom web page from JavaScript.

While using above method, we faced an issue from Outlook 2007 Client. "It opens the webpage in new window and authentication popup appears which does not happen in web client."

To overcome this issue we used CRM functions to open a new window as below:


function openWindow(url)
{

var name = "newWindow";

var width = 800;

var height = 600;

var newWindowFeatures = "status=1";

var oldWindowFeatures = "width=800,height=600,status=1";



// CRM function to open a new window with Windows Features

openStdWin(url, name, width, height, newWindowFeatures);



// CRM function to open a new window with default parameters

openStdWin(url, name);
}


Hope it would help.

Thursday, September 1, 2011

MS CRM 4.0 Interview Questions - Part 2 (Plugins)

What is Difference between synchronous and asynchronous plugin execution?
Synchronous plug-ins are executed in a pre-defined order as part of the main Microsoft Dynamics CRM event processing. Asynchronous plug-ins are queued and executed independently.

What is an Event Framework?
It is a technology that enables your custom solutions to be developed and integrated into the Microsoft Dynamics CRM server.

What is Unified Event Framework?
The new event framework unifies the separate plug-in and workflow models into a single event model. The unification of event models results in improved system event processing efficiency, a common programming interface for both plug-ins and workflow extensions, and a common deployment programming interface.

Is it possible for a plug-in to execute within the database transaction?
Yes, it is possible for a plug-in to execute within the Microsoft Dynamics CRM database transaction even though the plug-in was registered in a non-transaction pipeline stage

When validation occurs for user under which a plug-in executes?
Validation (privilege checks) of the system user account under which a plug-in executes occurs after the Pre-Event stage. Use caution when registering a pre-event plug-in that modifies data in an external data store because the user has not yet been validated in Microsoft Dynamics CRM when the plug-in code executes.

What is the event execution pipeline?
When a web service method is called by a plug-in or other application it creates a message in the Microsoft Dynamics CRM platform. The message contains business entity information and core operation information. The message is passed through the event execution pipeline where it can be read or modified by the platform core operation and any registered plug-ins. The event pipeline is divided into 5 stages, of which only 2 are available to custom developed plug-ins
  1. Pre-Event (BeforeMainOperationOutsideTransaction)
  2. Pre-Event (BeforeMainOperationInsideTransaction) - For internal use only
  3. Platform Core Operations (MainOperation) - No custom plug-ins can be registered in this stage
  4. Post-Event (AfterMainOperationInsideTransaction) - For internal use only
  5. Post-Event (AfterMainOperationOutsideTransaction)

What are Parent and Child Pipelines?
The event execution pipeline architecture provides the capability for a pipeline to initiate the execution of one or more subordinate pipelines in order to process a request. The originating pipeline is known as the "parent" while the subordinate pipeline is called the "child". Web service method calls typically start a parent pipeline while (internal) platform calls start a child pipeline.

How to get information of Parent Pipeline from Child Pipeline?
The context that is passed to plug-ins of the child pipeline will include the parent context that was executed immediately prior to the child pipeline's invocation. This will enable you to track the parent and child pipeline executions and get more information about what is going on.

How will you get to know that Plug-in is registered as Parent or Child Pipeline?
A plug-in can be registered to be executed from a parent pipeline or a child pipeline. At run time, a plug-in receives information as to how it was invoked through the InvocationSource property of the context that is passed as a parameter to the plug-in.

How will you invoke web service method in Child Pipeline?
In a child pipeline, you must instantiate the CrmService or MetadataService manually. Do not use the IPluginExecutionContext.CreateCrmService or IPluginExecutionContext.CreateMetadataService methods.

What would be the order of execution in a parent-child pipeline execution?
As an example, assume that parent pipeline A invokes child pipeline B during pipeline A's core platform operation. The order of execution will be as follows:
  • Pipeline A : all pre-events are processed.
  • Pipeline A : core platform operation, child pipeline B executed.
    • Pipeline B : all pre-events are processed.
    • Pipeline B : core platform operation.
    • Pipeline B : all post-events are processed.
  • Pipeline A : all post-events are processed.

How to avoid the ‘Denial of Service’ or Deadlocks in a Plug-in?
Infinite loop detection is automatically enabled in plug-ins that call the CreateCrmService method of IPluginExecutionContext to create a proxy to the Web service. For plug-ins that create a Web service proxy by instantiating CrmService, infinite loop detection can be enabled by setting the Web service instance's CorrelationTokenValue property. Plug-in code can obtain the Correlationid, CorrelationUpdatedTime, and Depth property values required by the CorrelationTokenValue instance from the execution context

How would you handle exceptions in Plug-ins?
To handle an error condition, your plug-in can throw InvalidPluginExecutionException exception to show a custom exception message to the user. When the platform receives this exception, it displays the exception message (System.Exception.Message) to the user.

On which message you would require to register the plug-in when an entity state is changed?
SetState and SetStateDynamicEntity messages

On which message you would require to register the plug-in when an entity data is populated in Grid?
Execute and RetrieveMultiple messages

What are the pre-requisite to deploy a plug-in assembly?
  1. It should be written in any .net 2.0 (or above) CLR compliant language
  2. Plug-in assembly must be signed, either by the Signing tab of the project's properties sheet in Microsoft Visual Studio 2005 or the Strong Name tool (sn.exe).
  3. You must add references to the Microsoft.Crm.Sdk and Microsoft.Crm.SdkTypeProxy assemblies that are provided in the SDK\Bin folder of the Microsoft Dynamics CRM SDK samples.
  4. You also have to add a reference for System.Web.Services
  5. Plug-ins must implement the Microsoft.Crm.Sdk.IPlugin interface.

How to pass data between plug-ins?
The message pipeline model provides a PropertyBag collection of System.Object named “SharedVariables” in the execution context that is passed through the pipeline and shared among registered plug-ins. At run time, plug-ins can add, read, or modify properties in the SharedVariables property bag. This provides a method of information communication among plug-ins. This feature is especially useful in chain processing or to communicate information between a plug-in registered for a pre-event and a plug-in registered for a post-event.
Note Only types that are XML serializable should be placed in SharedVariables. All types derived from BusinessEntity are XML serializable.
The following code example shows how to use SharedVariables to pass data from a pre-event registered plug-in to a post-event registered plug-in.

Happy Learning!!!!

Wednesday, July 27, 2011

MS CRM 4.0 Interview Questions - Part 1

1. When dynamic entity should be used?
Ans. The Dynamic Entity class is useful for when your code needs to work on entities and attributes that are not known at the time the code is written. However, this flexibility comes at a price. If your entities are already defined at code time, you should use the strong types provided for you in the WSDL.

2. Which is faster method to retrieve records 'CrmServices.Execute()' or CrmServices.Retrieve()'?
Ans. The CrmService common methods are faster than using the CrmService.Execute method with the corresponding message

3. When 'Execute' message is called in Plugin?
Ans. The Execute message in order to be executed whenever the Microsoft Dynamics CRM Web application retrieves data to populate a grid view

4. What is the Parent /child pipeline?

5. What service you will execute in plugin set as child pipeline?

6. How to create custom workflow and deploy in CRM?

7. How to create plugin and deploy in CRM?

8. Difference between Synchronous and Asynchronous plugin?

9. How to debut Asynchronous plugin?

10. How will you create new organization?

11. Can u modify the business unit in CRM?

12. How you will create user in CRM?

13. What is the difference between table and filtered views?

14. How can u remove system views?

15. How can you create plugin on converting lead to contact/account/opportunity event?

16. How can you deploy plugin and what are the options (settings) available while configuring (deploying) plugin?

17.  How to use impersonation in plugin?

18. How to define default parameter in CRM reports?

19. What web services available in CRM?

20. Which interface you will inherit to create plugin and how will u add your code?

21. If your asynchronous plugin is not working second time then what could be possible reason?

22. How will you handle the exceptions in plugin?

23. How will you check the error detail if any exception come in CRM?

24. How many types of relationships available in CRM?

25. What is the cascading?

26. Will you get the PreImage in create plugin, and PostImage in delete plugin?

27. What are the privileges required for the plugin registration
Ans: The system user account under which the plug-in is being registered must have the following organization wide security privileges:

prvCreatePluginAssembly
prvCreatePluginType
prvCreateSdkMessageProcessingStep
prvCreateSdkMessageProcessingStepImage
prvCreateSdkMessageProcessingStepSecureConfig

Note: The System Administrator and System Customizer roles have these privileges

28. How will you create web services in a plugin used in a child pipeline?

29. How you can add button on grid tool bar?

30. How you can add custom .aspx page in CRM?

31. Can you call plugin from custom button?

32. How many tabs can be added in a CRM page?

33. Can you add more then 8 tab in CRM?

34. Which method is faster RetrieveMultiple or FetchXml, which one should use and why?

35. How can we get data from multiple entities?

36. Difference between Retrieve and RetrieveMultiple?

37. How many events are available to change the form properties on CRM form?

38. How many services are available in CRM?

39. What is the default database structure when CRM is installed? (How many databases are created?)

40. How you can run workflows?

41. Describe Collision Rules for Import and Export or what are the Import Customization Conflicts?

If there are conflicts between objects in the import file and the target system, one of the following actions is taken:

Overwrite. The object definition in the import file overwrites the object on the target system.
Error. A SOAP exception that contains the error code is thrown.
New Object. A new object is created on the target system with the same name.
Skip. The object definition in the import file is skipped.

Retrieve single record from an entity using JavaScript in MS CRM 4.0

Here is a JavaScript method which can be used to retrieve a record from an entity using CRM Web Service. This method can be used to retrieve data from any CRM entity. It requires following parameters to be passed:
1.       entityName: Then schema name of an entity to be retrieved.
2.       entityId: record id form an entity.
3.       attributes: Array of attributes to be retrieved.


function RetrieveEntity(entityName, entityId, attributes)
{
    var result = null;
   
    if((entityName != null) && (entityName.length > 0)
    && (entityId != null) && (entityId.length > 0)
    && (attributes != null) && (attributes.length > 0))
    {
         try
         {
            var ColumnsSetAttributes = '';
            // Build columns to be retrieved
            for(var i = 0; i < attributes.length; i++)
            {
                ColumnsSetAttributes += " <q1:Attribute>" + attributes[i] + "</q1:Attribute>";
            }
           
            var XmlHeader = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
            "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
            GenerateAuthenticationHeader() +
            " <soap:Body>";   
            var RetrieveXml = XmlHeader +
            " <Execute xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>" +
            " <Request xsi:type='RetrieveRequest' ReturnDynamicEntities='true'>" +
            " <Target xsi:type='TargetRetrieveDynamic'>" +
            " <EntityName>" + entityName + "</EntityName>" +
            " <EntityId>" + entityId + "</EntityId>" +
            " </Target>" +
            " <ColumnSet xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:ColumnSet'>" +
            " <q1:Attributes>" +
            ColumnsSetAttributes +
            " </q1:Attributes>" +
            " </ColumnSet>" +
            " </Request>" +
            " </Execute>" +
            " </soap:Body>" +
            " </soap:Envelope>" +
            "";

            var RetrieveRequest = new ActiveXObject("Msxml2.XMLHTTP");
            RetrieveRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
            RetrieveRequest.setRequestHeader("SOAPAction"," http://schemas.microsoft.com/crm/2007/WebServices/Execute");
            RetrieveRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
            RetrieveRequest.setRequestHeader("Content-Length", RetrieveXml.length);
            RetrieveRequest.send(RetrieveXml);          
           
            var RetrieveResponseXml = RetrieveRequest.responseXML;
            //Check for errors.
            if((RetrieveResponseXml == null) || (typeof(RetrieveResponseXml) == "undefined"))
            {                  
                alert("Error: No response received.");
            }
            else
            {
                var errorContactIdCount = RetrieveResponseXml.selectNodes('//error').length;
                if(errorContactIdCount != 0)
                {
                    var msg = oXml.selectSingleNode('//description').nodeTypedValue;              
                    alert(msg);
                }
                else
                {
                    //select the node text
                    var QueryBusinessResponseXml = RetrieveResponseXml.selectNodes("//BusinessEntity");
                    result = QueryBusinessResponseXml;
                }
            }
        }
        catch(e)
        {
            alert('Error occurred: ' + e.description);
        }
    }   
    return result;
   
}

Example: Retrieve name from a contact record:

//Example: To retrieve name from a contact
var EntityName = "contact";
var EntityId =  crmForm.ObjectId;//contactid
var AttributeList = new Array();
AttributeList[0] =  "name";

var responseXml = RetrieveEntity(EntityName,EntityId,AttributeList);

if(responseXml != null)
{
    //Get Investor Activity Id from response xml.
    var ContactNameNode = responseXml[0].selectSingleNode("//Property[@Name='name']");
    var CotactName = '';
    if(ContactNameNode != null && ContactNameNode.childNodes[0] != null)
    {
        CotactName = ContactNameNode.childNodes[0].text;
    }
}

Sunday, July 24, 2011

How to show related records as Multi Select Checkbox List in MS CRM 4.0 through JavaScript

Natively MS Dynamics CRM 4.0 displays many-to-many relationships as Associated Views. We cannot display records from related entity at any other place on the other entity.  To display related records as check boxes on CRM form we need to either create custom web page or write JavaScript.
Following are the steps to create a Multi Select checkbox list to display related record on CRM Form through JavaScript:
1.       Create a many-to-many relationship
2.       Add OnLoad event on CRM Form
3.       Add OnSave event on CRM Form
4.       Associate/De-associate Inquiry from Client Request through Create and Update Plugins
Create two new custom entities and add many-to-many relationship between them:
1.       Create a new entity called Inquiry.
2.       Publish the Inquiry entity.
3.       Create an another entity called Client Request
4.       Add a section on the CRM Form called ‘Inquiries’ to display list of inquiries.
5.       Create a N:N relationship from Client Request to Inquiry entity.
6.       Publish the Client Request entity.
7.       Open Inquiry entity and add some new inquiries.
Now entities are configured and having some sample data. We are now ready to add JavaScript code on CRM Form to display Inquiry options on Client Request entity as a check box list.
Add an onLoad event on Client Request entity to display Inquiry options as check box list:
1.       Using CRM Web Services, retrieve all inquiries from Inquiry entity. (How to retrieve multiple records through JavaScript )
2.       Using CRM Web Services, retrieve all selected inquiries from relationship table which is created by CRM automatically when we create a many-to-many relationship.  Select only inquiries which are associated with current Client Request. This should be done only in case of retrieving Client Request. Check the FormType property of CRM Form and if Update mode then only retrieve selected inquiries. ( How to retrieve multiple records from link entity through JavaScript )
3.       Call “GenerateMultiSelectList()” method and pass the list of all inquiries and list of selected (associated) inquiries and the name of element (location) where to display checkbox list.
Add an onSave event on Client Request entity to save selected inquiries:
1.        Call “SaveMultiSelectList()” method and pass the section name, in our case ‘inquiries’. This method will provide you following semicolon (;) separated lists:
a.       List: This provides Inquiry ID list of all inquiries
b.      SelectedList: This provides Inquiry ID list of selected inquiries
c.       SelectedNameList: This provides Inquiry Name list of selected inquiries.
2.       Now you have to set each list in any of the CRM field to save into CRM database
Associate/De-associate Inquiry from Client Request:
1.       Now finally you have to associate or de-associate inquiries from Client Request based on the user selection. For this purpose you need to create plugins on Create and Update message and add/remove. Use ‘ AssociateEntitiesRequest’ class of CrmService to add a link between Inquiry and Client Request entity instances for a many-to-many relationship.  A complete example is given in CRM SDK at MSDN(http://msdn.microsoft.com/en-us/library/cc151609.aspx )
OnLoad JavaScript Code:

//Method to remove all child nodes from an html element
function RemoveAllChilds(element)
{
    while(element.hasChildNodes())
    {
        element.removeChild(element.childNodes[0]);
    }
}

//Method to generate check boxes and display them into an area specified and make the default selection
// parentArea   : An HTML element where checkboxes will be added
// checkBoxList : List of items that will be displayed as checkboxes
// selectedList : List of items that will be selected by default
// listType     : Name or type of the list
function GenerateMultiselectCheckboxes(parentArea, checkBoxList, selectedList, listType)
{

    // Clear the container element
    RemoveAllChilds(parentArea);
   
    tableTag = document.createElement("table");
    tableTag.setAttribute("id","tbl_multiselect" + listType);
    tableTag.setAttribute("width","100%");
    tbodyTag = document.createElement("TBODY");
   
    var NoOfOptions = checkBoxList.length;
    var NoOfRows = 0;
    if(NoOfOptions <= 4)
    {
        NoOfRows = 1;
    }
    else
    {
        NoOfRows = (checkBoxList.length /4);
    }
   
    for(var iRow = 0; iRow <  NoOfRows; iRow++)
    {
        mycurrent_row = document.createElement("tr");
        for(var iCell = 0; iCell < 4 ; iCell++)
        {
            var addInput;
            var OptionIndex = iCell + (iRow * 4);
            if(OptionIndex < NoOfOptions)
            {
                var pOption = checkBoxList[OptionIndex][1];   
                var cellId = checkBoxList[OptionIndex][0];
                if(selectedList != null && typeof(selectedList) != "undefined" && selectedList.indexOf(cellId)> 0)
                {
                    addInput = document.createElement("<input type='checkbox' CHECKED  style='border:none; width:25px; align:left;' />" ); 
                }
                else
                {
                    addInput = document.createElement("<input type='checkbox'  style='border:none; width:25px; align:left;' />" ); 
                }
               
                         
                var addLabel = document.createElement( "<label style='align:left;' />");   
                addLabel.innerText = pOption;
            
                mycurrent_cell = document.createElement("td");
                mycurrent_cell.setAttribute("width","25%");
                mycurrent_cell.setAttribute("id",cellId);
                mycurrent_cell.setAttribute('align', "left");
                mycurrent_cell.appendChild(addInput);  
                mycurrent_cell.appendChild(addLabel);  
            }
            else
            {
                mycurrent_cell = document.createElement("td");
                mycurrent_cell.setAttribute("width","25%");
                mycurrent_cell.setAttribute("id",0);
                mycurrent_cell.setAttribute('align', "left");
                currenttext = document.createTextNode("");
                mycurrent_cell.appendChild(currenttext);
            }
            mycurrent_row.appendChild(mycurrent_cell);
        }
       
        tbodyTag.appendChild(mycurrent_row);
       
    }
    tableTag.appendChild(tbodyTag);
    return tableTag;

}

// Method to generate Multi Select List based on the list of items
// list         : List of items to be displayed as multi select check boxes
// selectedList : List of items to be selected by default
// listType     : Name of the control which will hold the multi selct list, this should be unique on the CRM.
function GenerateMultiSelectList(list, selectedList, listType)
{
   
    var row_MultiSelect = document.getElementById("tr_multiselect" + listType);
    var cell_MultiSelect = null;
    if(row_MultiSelect != null && typeof(row_MultiSelect) != "undefined")
    {
        cell_MultiSelect = row_MultiSelect.childNodes[0];
        if(cell_MultiSelect == null || typeof(cell_MultiSelect) == "undefined")
        {
            cell_MultiSelect = document.createElement("td");
            cell_MultiSelect.setAttribute('id', "td_multiselect" + listType);
            cell_MultiSelect.colSpan = 4;
            row_MultiSelect.appendChild(cell_MultiSelect);
        }
    }
    else
    {
        //Find the container element which will hold the multiselect list.
        var arrTD = document.getElementsByTagName("td");
        var FieldContainer = "";
        for(var i = 0; i < arrTD.length; i++)
        {
            currTD = arrTD[i];
            if(currTD != null && typeof(currTD) != "undefined" && currTD.innerText.toLowerCase() == listType.toLowerCase())
            {
                FieldContainer = currTD;
                break;
            }
        }
       
        parentArea = FieldContainer.childNodes[0].childNodes[1];
   
        row_MultiSelect =  document.createElement("tr");
        row_MultiSelect.setAttribute("id", "tr_multiselect" + listType);
        row_MultiSelect.setAttribute("vAlign", "top");
        parentArea.appendChild(row_MultiSelect);
       
        cell_MultiSelect = document.createElement("td");
        cell_MultiSelect.setAttribute('id', "td_multiselect" + listType);
        cell_MultiSelect.colSpan = 4;
        row_MultiSelect.appendChild(cell_MultiSelect);
    }
   
    var containerTable = GenerateMultiselectCheckboxes(cell_MultiSelect, list, selectedList, listType);
   
    cell_MultiSelect.appendChild(containerTable);  
 
}

function GetListFromXmlResponse(responseXml)
{
     var arrListItem = new Array();
   
    if(responseXml != null)
    {
        for(i = 0; i < responseXml.length; i++)
        {
            arrItem = new Array(responseXml[i].childNodes[0].text,responseXml[i].childNodes[1].text);
            arrListItem[i] = arrItem;
        }
    }
    return arrListItem;
}


//Example

//Retrieve all inquiries
var responseXml = RetrieveMultiple();

InquiryList = GetListFromXmlResponse(responseXml);

//Note: List type should be same as section name where you want to display the Inquiries as check boxes;
GenerateMultiSelectList(InquiryList, null,"inquiries");


OnSave JavaScript Code:

var List = '';
var SelectedList = '';
var SelectedNameList = '';

function SaveMultiSelectList(listType)
{
    var tbl_MultiSelect = document.getElementById("tbl_multiselect" + listType);
   
    var CheckBoxList = tbl_MultiSelect.getElementsByTagName("td");
    if(typeof(CheckBoxList) != "undefined" && CheckBoxList != null && CheckBoxList.length > 0)
    {
        for(i = 0; i < CheckBoxList.length ; i++)
        {
            var CheckBox = CheckBoxList[i];
            if(typeof(CheckBox) != "undefined" && CheckBox != null && CheckBox.childNodes.length > 0)
            {
                if(CheckBox.id != null && CheckBox.id != 0)
                {
                    var Id = CheckBox.id;
                    var IsChecked = CheckBox.childNodes[0].checked;
                    var Name = CheckBox.childNodes[1].innerText;
                    List = List + ";" + Id
                    if(IsChecked)
                    {
                        SelectedNameList = SelectedNameList + ";" + Name;
                        SelectedList = SelectedList + ";" + Id;
                    }
                }
            }
        }
    }
}

SaveMultiSelectList("inquiries");