Tuesday, January 31, 2012

Step by step plugin tutorial using Developer's Toolkit Part 3

This blog is an extension of my last blog Step by step plugin tutorial using Developer's Toolkit Part 2. We used “Create Wrapper” method to generate strongly typed classes. In this blog, we will use OrganizationServiceContext to create “Task” entity instead of using service.Create() method. To use OrganizationServiceContext in the plugin, we need to add reference to Microsoft.Xrm.Sdk.Client at the top of the class.
using Microsoft.Xrm.Sdk.Client;
Now create an instance of OrganizationServiceContext by passing the OrganizationService as shown below
// TODO: Implement your custom Plug-in business logic.
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
//ITracingService tracingService = localContext.TracingService;
//create a service context
var ServiceContext = new OrganizationServiceContext(service);
Now replace the
service.Create(task);
with
ServiceContext.AddObject(task);
ServiceContext.SaveChanges();
Deploy the plugin and test it.

Advantages of using OrganizationServiceContext

The biggest advantage of using OrganizationServiceContext is that we can track multiple entities/operations and save all the changes with ServiceContext.SaveChanges(); statement. Have a look at this article on MSDN. 

Wednesday, January 18, 2012

Step by step plugin tutorial using Developer's Toolkit Part 2

This is a second part of my last blog step-by-step-plugin-tutorial Developer’s Toolkit Part 1. In the last blog, we created a plugin using late binding. In this blog we use early binding (strongly typed classes) to create the same plugin. This is another advantage of using the Developer’s Toolkit. We can generate the strongly typed classes by click of the mouse. We don’t have to use CrmSvcUtil Command-Line Utility and copy the generated file to our plugin Project. I am going to use the same solution I have used for my last blog.
Please read the last blog before starting this one. Here are the steps.
  1. Open the CRM Explorer. Right Click on the Entities node and select “Generate  Wrapper”. It will generate the strongly type classes and add it to the Plugins project. The name of the generated file will be Entities.cs.c1 c3
  2. Now expand the Entities node. Right Click on Account Entity and select “Create Plug-in”. It will display a following dialog. This time we are creating a plugin on update event. Enter the values as shown the screen shot. You can change the class name if you like and press OK. It will create a new file “PostAccountUpdate.cs” in the plugins project.c4
  3. Open the “PostAccountUpdate.cs” file. Add the reference to Entites.cs file to use the strongly typed classes.
  4. Copy the ExecutePostAccountCreate() function code from PostAccountCreate.cs created in last blog and paste it in ExecutePostAccountUpdate() function of “PostAccountUpdate.cs”.
  5. Replace the following lines in copied code of ExecutePostAccountUpdate() function
    //create a task
    Entity task = new Entity("task");
    task["subject"] = "Account number is missing";
    task["regardingobjectid"] = new EntityReference("account",entity.Id);
    
    //adding attribute using the add function
    // task["description"] = "Account number is missng for the following account. Please enter the account number";
    task.Attributes.Add("description", "Account number is missng for the following account. Please enter the account number");
                            
    // Create the task in Microsoft Dynamics CRM.
    service.Create(task);
    
    with
    //create a task
    Task task = new Task();
    task.Subject = "Account number is missing";
    task.RegardingObjectId = new EntityReference("account", new Guid(context.OutputParameters["id"].ToString()));
    task.Description = "Account number is missng for the following account. Please enter the account number";
    
    // Create the task in Microsoft Dynamics CRM.
    service.Create(task);
    
    
    We replaced the Entity object with Task object and we used task.Description in place of task["description"]. Early binding (strongly typed classes provides us all the crm entities objects, their properties and methods.
  6. Now right click on CRM Package project and select deploy. It will register the plugin assembly as well as step for the plugin. Click on CRM Explorer to check the deployed plugin as shown in the following screen shot. There are two plugins registered, one for post update event that we just created and one for post create event we created in last blog. Update an account to test the plugin.       c6

Advantages for using early binding

Here is the link to explain the differences between early binding and late binding. I am listing few of advantages using early binding.
  1. The biggest advantage of using early binding is that we have access to all the CRM entities(account, contact, opportunity, task etc) their attributes and their relationships.In late binding we use the Entity (dynamic entity) to work with all the CRM entities.
  2. Access to visual studio intellisense while writing code.In the following screen shot, we create an instance of Task entity and when we type Task, it will display all the attributes and methods belong to task entity.c5
  3. There are less chances of misspelling the attributes names. Early bound references are checked at compile time. for e.g if we spell the attribute name wrong, you won’t able to compile the code. In late binding, it will hard to find out if we misspell the attribute name as references will be checked at run time.

Monday, January 16, 2012

Step by step plugin tutorial using Developer's Toolkit Part 1

I was looking at developer’s toolkit shipped with CRM2011 SDK. There are few blogs out there on how to create plugins using developer's tool kit. Most of the blogs (more or less) are the copy of  “developer toolkit user's guide” that comes with the toolkit.

Here is link to Sam’s blog that explains each project in developer’s toolkit. MSDN blog also have similar contents. In this blog I am going to create a sample plugin using developer’s toolkit. It is a copy of one of my earlier blog(Step by step plugin tutorial for CRM 2011) .

Install the developer’s toolkit.The Developer toolkit for Microsoft Dynamics CRM 2011 was released as part of UR5 SDK release and is available for download here.


  1. Create a new solution in CRM2011. I named my solution “CRM Plugin Solution”. This is optional but I would recommend you do that.
  2. Open Visual Studio 2010. Select File—New –Project. It will display new project templates dialog as shown in the screen sheet belowp1
  3. Select “Dynamics CRM 2011 Package” project. This is also optional. You can go ahead and select “Dynamics CRM 2011 Plugin Library”, But then you cannot deploy the plugin straight from the Visual Studio. You have to use Plugin Registration tool to register the plugin. Enter the name of project/solution.
  4. VS studio will display following dialog.Enter you CRM 2011 server details.Select the solution name we created in step 1 and click okp2
  5. Now right click on the solution and add “Dynamics CRM 2011 Plugin Library” project to the solution. The plugin project will already have a plugin.cs file.
  6. Now sign the plugin assembly. Right click on Plugin Project and select properties. Select Signing tab from left navigation of project property page. On the Signing tab, select the Sign the assembly check box and set the strong name key file of your choice.At a minimum, you must specify a new key file name. Do not protect your key file by using a password.
  7. If You cannot see the “CRM Explorer” window on the upper left side of the VS studio, click on View menu and select “CRM Explorer”. p3
  8. Now expand “Entities” Node. Right Click the entity on want to create the plugin for and select “Create Plugin”.p4
  9. It will display a following screen.It is equivalent to “Create Step” screen in plugin registration tool. The dialog will pick up the name of the entity and other information. Choose the message and the pipeline stage. You can also change of the Class attribute. Press Ok.pn5
  10. It will create a .cs file with name mentioned in “Class” attribute in screen shot above. Double click on the class file(PostAccountCreate) and scroll down to following lines of code. You write your business logic here.
    protected void ExecutePostAccountCreate(LocalPluginContext localContext)
    {
       if (localContext == null)
       {
           throw new ArgumentNullException("localContext");
       }
       // TODO: Implement your custom Plug-in business logic.
    }
  11. The first thing you will do is to get the plugin context, CRMService instance and TracingService instance using localContext passed to the function. All these objects are defined in the built in plugin.cs class.
    IPluginExecutionContext context = localContext.PluginExecutionContext;
    IOrganizationService service = localContext.OrganizationService;
    //ITracingService tracingService = localContext.TracingService;
  12. Here is code. It will check if the “account number” is null or empty and  create a task for a user to enter the account number.
    protected void ExecutePostAccountCreate(LocalPluginContext localContext)
    {
        if (localContext == null)
        {
            throw new ArgumentNullException("localContext");
        }
    
        // TODO: Implement your custom Plug-in business logic.
        // Obtain the execution context from the service provider.
        IPluginExecutionContext context = localContext.PluginExecutionContext;
        IOrganizationService service = localContext.OrganizationService;
        //ITracingService tracingService = localContext.TracingService;
    
    
        // The InputParameters collection contains all the data passed in the message request.
        if (context.InputParameters.Contains("Target") &&
        context.InputParameters["Target"] is Entity)
        {
            // Obtain the target entity from the input parmameters.
            Entity entity = (Entity)context.InputParameters["Target"];
                    
            //EntityReference pp = entity.GetAttributeValue("primarycontactid");
            //tracingService.Trace(pp.LogicalName);
                   
                    
            try
            {
                //check if the account number exist
    
                if (entity.Attributes.Contains("accountnumber") == false)
                {
    
                    //create a task
                    Entity task = new Entity("task");
                    task["subject"] = "Account number is missing";
                    task["regardingobjectid"] = new EntityReference("account", new Guid(context.OutputParameters["id"].ToString()));
    
                    //adding attribute using the add function
                    // task["description"] = "Account number is missng for the following account. Please enter the account number";
                    task.Attributes.Add("description", "Account number is missng for the following account. Please enter the account number");
                            
                    // Create the task in Microsoft Dynamics CRM.
                    service.Create(task);
    
    
                }
            }
    
            catch (FaultException ex)
            {
                throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
            }
    
        }
    
    }
    I also left few commented lines in the code to show “How to use tracingservice to write in trace log”. You will able to see the trace only if there is an error in the plugin.
  13. Now right click on CRM Package project we created in step 2 and select deploy. It will register the plugin assembly as well as step for the plugin. Click on CRM Explorer to check the deployed plugin as shown in the following screen shot.pn1
  14. Create a new account and test the plugin.

Friday, December 30, 2011

Step by step tutorial to add an entity URL to an email in a workflow

Rollup 5 introduced some new features in CRM2011. One of them is to add  an entity URL to an email in workflow. Before rollup 5, it used to be a  complicated process.We don't need to create custom workflow assemblies to this any more.. Still, there are a lot of people asking the same question “How to add entity URLs to emails in workflows” in CRM Forums.
Here is the step by step tutorial to add an entity URL to an email in a workflow.
1.    Start a new workflow.
2.    To send an email. Click on “Add Step” and choose “Send Email”. It will open up a following screen.pic 
3.    Add the information as required and to add the hyperlink, click on hyperlink icon shown in red circle in the above screen shot. It will open up a following screen.
pic2
4.    In “Text to display”. Enter the text to you would want to display. I am displaying the full name of the contact. It can be any string.
5.    Select the “URL” text box . When you look through the available fields. You can see a new option “Record URL (Dynamic)”. Click on that and press Ok.  The email will look like following screen.pic3  6.    Press save and close. Publish the workflow and you are good to go.

Monday, December 26, 2011

CRM2011 Subgrids and JavaScript

I have been thinking of bloging about this topic from last 6 months. I wanted to get an aggregate of numeric/money field in the grid. It is very easy to do, if subgrid contains only one page. But How would you get the aggregate if subgrid has more than 1 pages.

I posted this question on the forums and I never get an answer. I still don't have a solution for this problem.
Anyway....

The following sample code displaying the message box with the aggregate of “Estimated Revenue” field  of the opportunity.ce
function subGridOnload() 
{ 
 //debugger;
 var grid = Xrm.Page.ui.controls.get('Opps')._control;
 var sum =0.00;
 //if  (grid.readyState!="complete") 
 //{ 
 // delay one second and try again. 
 //setTimeout(subGridOnload, 1000); 
 //return; 
 //} 

 if  (grid.get_innerControl()==null)
 { 
  setTimeout(subGridOnload, 1000); 
  return; 
 } 
 else if (grid.get_innerControl()._element.innerText.search("Loading")!= -1)
 {
  setTimeout(subGridOnload, 1000); 
  return;
 }

 var ids = grid.get_innerControl().get_allRecordIds(); 
 var cellValue;
 for(i = 0; i < ids.length; i++) 
 { 
     if (grid.get_innerControl().getCellValue('estimatedvalue', ids[i]) !="")
     { 
       cellValue = grid.get_innerControl().getCellValue('estimatedvalue', ids[i]); 
       cellValue = cellValue.substring(2); 
       cellValue = parseFloat(cellValue);  
       sum = sum + cellValue;
     }
 
 }//end for   
 alert(sum);
}
I also noticed that  grid.readyState!="complete" does not work all the time.  It happens when the control is already loaded but the grid is still retrieving the data. So I changed the code to check if the records are already loaded.
See you guys……

Monday, December 19, 2011

Updating custom fields on synced outlook contacts in crm2011

CRM2011 does not support synching custom fields between CRM2011 and synced Outlook Contacts.
You can’t even select the fields to sync between CRM and Outlook. The add-in will update the custom fields between synced Outlook contacts with CRM2011.

Software Requirements:

This solution is tested on windows 7 and outlook 2010 only.

Solution components:

The solution consists of 2 components.
  • UpdateContactAddin_1_0_managed.zip (CRM2011 Managed solution)
  • OutlookAddin.zip (Outlook Addin)

1. UpdateContactAddin_1_0_managed.zip :

Download the file and import the solution. The solution creates a custom entity called “syncmapping”. The entity contains two main fields “CRM Field” and “Outlook Field”. The entity will map the fields needed to be updated between CRM2011 Contacts and Outlook Contacts. Before you add any data into the entity, go to the default solution and customize the entity to display in workplace or settings area.

For e.g. In above screen “accountrolecode” (Display Name Role) field in contact entity will update the User1 field or “User Field 1” in Outlook. clip_image004
You can choose multiple fields to update/synced Outlook Contacts as shown in the screen shot below

Note: The display name in both in Outlook and CRM2011 are different than the names used in the code. We need the “Name” field of the CRM2011. To get the proper name of the Outlook field please follow this link http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.contactitem_properties.aspx
For e.g. The name of “User Field 1” field is User1. “User Field 1” is just a display name. If the field does not exist in Outlook, the solution will create a new user defined field in Outlook.

2. OutlookAddin.zip

Extract the OutlookAddin.zip file and run the SetupUpdateContact exe. It will add a custom tab to the ribbon as shown in the following screen shot.


When the user clicks on “Update Contact”, it will display a following dialog. Enter all the values and press Update.

The above screen shot displays the values for CRM Online.

The above screen shot displays the values for on-premise CRM Deployment.
At the end of the process, the system will display a following message

Facts:
This solution updates text fields in outlook only. If you pick an optionset from CRM2011, the solution will get the text value of the field and update the field in Outlook.
The solution uses the update method to update the individual contacts. The solution does not have any automatic or scheduled syncing mechanism.
This solution is smart enough to update the contacts for the selected organization. If you are synced contacts from different organization. The system will update the contacts of the organization selected in a addin dialog.

Tips:

  • Setup the sync fields in syncmapping entity before pressing the update button
  • Please sync your outlook contacts before trying this solution.
Download this solution.

Sunday, November 13, 2011

CRM2011 Setup/Upgrade Errors and Resolutions

This is the second part of my last blog Installing CRM2011 with Precreated AD Groups.
The following are some of the errors and their resolutions encountered during installation/upgrade

Error 1

SQLSERVERAGENT (SQLSERVERAGENT) service is not running on the server ......

clip_image002


Resolution:

· Check if SQLSERVERAGENT service is running
· Open the port 445 for SQL Server.



Error 2

During the import of the organizations the following warning was received.
"Fragmented indexes were detected in the Microsoft Dynamics CRM database",

Resolution:


Re-index the organisation databases
USE MyDatabase
GO
EXEC sp_MSforeachtable @command1="print '?' DBCC DBREINDEX ('?', ' ', 80)"
GO
EXEC sp_updatestats
GO
Updating statistics ensures that queries compile with up-to-date statistics

Error 3

The following error message was received when testing the email router:
Type 'System.ServiceModel.Channels.ReceivedFault' in Assembly 'System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable

Resolution:


Add the account running the email router services to PrivUserGroup security group.

Error 4

The following error message was received when accessing the reports from any of the organizations:
Microsoft.Crm.Web.Reporting.SrsReportViewer.SetExecutionCredentials(ServerReport reportObj) Cannot create a connection to data source 'MSCRM'. (rsErrorOpeningConnection)
The reason was SSRS connector(reporting extensions) was installed using user other than deployment account. The SSRS service account was missing in privreportinggroup group.

Resolution:


  • · Add SSRS service account to privreporting group.
  • · Reinstall the reporting extension again using deployment account.
The process to resolve was as follows:
  1. 1. Uninstall the Reporting Extensions.
  2. 2. Go to the CONFIG DB (MSCRM_CONFIG) of CRM and update your organization's row in the Organization table to set the AreReportsPublished boolean field to FALSE.
  3. 3. Re-install the Reporting Extensions and they should publish the reports again.
Note: You will see the message about installation is republishing the reports again

FIXES FOR THE UPGRADED ORGANISATIONS

The section contains information on the issues encountered that required fixing for the upgraded organisations.

Issue 1

Unknown labels in settings group as shown in the screen shot below. This had happened to all four organisations.
image clip_image006
             Before                              After



Resolution:

Follow the Microsoft article for resolution: http://support.microsoft.com/kb/2530358.


Issue 2

The main tab is closed by default as shown in the screen shot below:
image
It is noted that this happened on multiple different locations throughout all the organisations.


Resolution:

  • Open the form in customisation mode.
  • Expand the tab, save the changes and then publish the changes.
There were few other things that did not work after upgrade. One of them was, the client has custom button to “Create Phone Cal” on contact and account form. The button was using builtin javascript function “locAddActTo(4210)”. I need to change the ribbon and javascript to fix that that function does not exist in CRM 2011.

clip_image002[9]
That’s all from me.