Skip Ribbon Commands
Skip to main content

Brite Global Blogs




Connect with Brite Global


Like us on Facebook, add us to your LinkedIn network, view our videos on YouTube or subscribe to our blog.

Facebook Linked In You Tube Blog and RSS
Mar 30
Detecting Duplicate Contacts

Although CRM provides a duplicate detection process that can be configured using the User Interface, many time when developing application for CRM, such as Import Manager or Synchronization application, you require to create your own duplicate detection rules, execute the duplicate detection process and retrieve the results of the duplicates from within your application.

The code samples below show how to create a Duplicate Detection Rule, execute the duplicate detection process and retrieve the results of the duplicate records.

To create a Duplicate Detection Rule, we use the DuplicateRule class, and provide a name for the rule and the entity name that will be used for the rule. In the example below, we create a rule that will check for duplicate email addresses in the contact record. After creating the rule, we need to specify the condition for the rule. The DuplicateRuleCondition class allows us to specify the attribute for the condition, and the type of rule that will be used. In the example below we use the emailaddress1 field and the base and matching attribute, and we set the match as exact match (an OptionSet value of 0).

When the rule and the rule condition have been created, we publish the rule by calling the execute method of the CRM service with the PublishDuplicateRuleRequest and PublishDuplicateRuleResponse.

Note that the process to publish a duplicate detection rule can be someone of a lengthy process, so we call the WaitForAsyncJobToFinish method to wait until the job is complete.

 

private Guid CreateDuplicateDetectionRule()

{

    DuplicateRule rule = new DuplicateRule()

    {

        Name = "Contacts with the same Email Address",

        BaseEntityName = Contact.EntityLogicalName,

        MatchingEntityName = Contact.EntityLogicalName

    };

    rule.Id = CRMHelper.xrm5.Create(rule);

 

    DuplicateRuleCondition emailCondition = new DuplicateRuleCondition()

    {

        BaseAttributeName = "emailaddress1",

        MatchingAttributeName = "emailaddress1",

        OperatorCode = new OptionSetValue(0), // value 0 = 'exact match'

        RegardingObjectId = rule.ToEntityReference()

    };

    CRMHelper.xrm5.Create(emailCondition);

 

    PublishDuplicateRuleRequest publishRequest = new PublishDuplicateRuleRequest()

    {

        DuplicateRuleId = rule.Id

    };

 

    PublishDuplicateRuleResponse publishResponse =

        (PublishDuplicateRuleResponse)service.Execute(publishRequest);

 

    WaitForAsyncJobToFinish(publishResponse.JobId, 60);

    return rule.Id;

}

 

The WaitForAsyncJobToFinish method call queries the AsyncOperation entity every 1 second to check if the process has been completed.

Once the process has been completed, the method exits and application can continue processing.

Note that since this is a lengthy process, additional code can be added in case it takes more than the maximum second value.
Normally the 60 seconds passed from the previous method is more than sufficient to create a Duplicate Detection Rule, but at times based on environment, more time will be needed.

 

private void WaitForAsyncJobToFinish(Guid jobId, int maxSeconds)

{

    for (int i = 0; i < maxSeconds; i++)

    {

        var asyncJob = service.Retrieve(AsyncOperation.EntityLogicalName,

                jobId, new ColumnSet("statecode")).ToEntity<AsyncOperation>();

 

    if (asyncJob.StateCode.HasValue && asyncJob.StateCode.Value == AsyncOperationState.Completed)

        return;

        System.Threading.Thread.Sleep(1000);

    }

}

 

The CheckDuplicateEmails method shown below is the entry point of the application. The method will first call the CreateDuplicateDetectionRule before proceeding with the running the duplicate detection process. If you already have a Duplicate Detection Rule in your environment, you can skip calling the CreateDuplicateDetectionRule method and the Delete method at the end of the method.
We create a new BulkDetectDuplicatesRequest, passing a job name, query expression that specifies the name of the entity and columns to return, a recurrence pattern and start time. The ToRecipients and CCRecipients are required fields as part of the request (if omitted, process will fail). We call the execute method passing the BulkDetectDuplicatesRequest, and get a BulkDetectDuplicatesResponse class. Since this process is also asynchronous, we will call the WaitForAsyncJobToFinish method passing the job identifier and the amount of seconds to wait.
After the Bulk Detect Duplicates process has been complete we can query the DuplicateRecord entity passing the asyncoperationid field to retrieve a list of all the duplicate contact records that were detected. The method will the return the duplicate identifiers to the calling method.
As previously mentioned, the Delete call should be omitted if you are using an existing Duplicate Detection Rule.

 

public List<Guid> CheckDuplicateEmails()

{

    Guid ruleId = CreateDuplicateDetectionRule();

 

    BulkDetectDuplicatesRequest request = new BulkDetectDuplicatesRequest()

    {

        JobName = "Detect Duplicate Contacts",

        Query = new QueryExpression()

        {

            EntityName = Contact.EntityLogicalName,

            ColumnSet = new ColumnSet(true)

        },

        RecurrencePattern = String.Empty,

        RecurrenceStartTime = DateTime.Now,

        ToRecipients = new Guid[0],

        CCRecipients = new Guid[0]

    };

 

    BulkDetectDuplicatesResponse response = (BulkDetectDuplicatesResponse)service.Execute(request);

    WaitForAsyncJobToFinish(response.JobId, 120);

 

    QueryByAttribute query = new QueryByAttribute()

    {

        ColumnSet = new ColumnSet(true),

        EntityName = "duplicaterecord"

    };

    query.Attributes.Add("asyncoperationid");

    query.Values.Add(response.JobId);

    EntityCollection results = service.RetrieveMultiple(query);

 

    var duplicateIds = results.Entities.Select((entity) => ((DuplicateRecord)entity).BaseRecordId.Id);

 

    service.Delete(DuplicateRule.EntityLogicalName, ruleId);

    return duplicateIds.ToList<Guid>();

}

 

Finally, if we need to use the duplicate identifiers that were retrieved from the CheckDuplicateEmails method, we can use the code below to display them in a grid.
The code sample below uses the Infragistics Grid, but any grid control can be used to display the results.

 

List<Guid> duplicates = CRMHelper.crm.CheckDuplicateEmails();

 

if (duplicates.Count > 0)

{

    foreach (Guid contactid in duplicates)

    {

        Entity contact = CRMHelper.crm.RetrieveContact(contactid);

 

        int rowid = dgvDuplicates.Rows.Add();

        DataGridViewRow row = (DataGridViewRow)dgvDuplicates.Rows[rowid];

        row.Cells[0].Value = contactid.ToString();

        row.Cells[2].Value = contact.Attributes["fullname"].ToString();

        row.Cells[3].Value = contact.Attributes["emailaddress1"].ToString();

    }

}

 

Mar 25
Bulk Data API ExecuteMultipleRequest in UR12

The ExecuteMultipleRequest message was added to the December 2012 Service Update (UR12) in CRM Online and CRM On-Premise, which accepts a collection of message requests, executes them in the order of the input collection and can return a collection of responses that contain the response for each message that occurred or if an error occurred. The CRM SDK version 5.0.13 is required to use the ExecuteMultipleRequest.

Each message request in the collection is processed in a separate database transaction, and the ExecuteMultipleRequest is executed by using the OrganizationService Execute method.

The ExecuteMultipleRequest behaves in the same way as if each message request in the input request collection was executed separately, except that it is processed with better performance. Plug-ins and workflow messages are executed the same way as if each execute message would be called separately.

The sample code below shows how to use the RetrieveMultiple request to retrieve multiple entity records from the database, modify theses records and update them back to the database using the ExecuteMultipleRequest.

The initial step is to instantiate the ExecuteMultipleRequest class so that any updates can be added to the class

ExecuteMultipleRequest multipleRequest = new ExecuteMultipleRequest()
{
  
Settings = new ExecuteMultipleSettings()
   {

       ContinueOnError = false,

       ReturnResponses = true

    },

    Requests = new OrganizationRequestCollection()

};


We then need to retrieve the records from the CRM database that we want to make modifications to, and make the updates. When calling the update method we are not sending the request to CRM, but only adding the update request to the ExecuteMultipleRequest requests collection:

// Retrieve records and make modifications to existing records

EntityCollection contacts = CRMHelper.crm.RetrieveContacts();

if (contacts.Entities.Count > 0)

{

   foreach (Entity contact in contacts.Entities)

    {

       Guid contactid = contact.Id;

       string emailAddress = contact.Contains("emailaddress1") ?
       contact.Attributes["emailaddress1"].ToString() : "";

       if (!string.IsNullOrEmpty(emailAddress))

       {

          contact.Attributes["xrm_profileurl"] = "http://www.contoso.com/register.aspx?eid=" +
             contactid.ToString();

          contact.Attributes["xrm_unsubscribeurl"] = "http://www.contoso.com/communications.aspx?eid="
             + contactid.ToString();

          UpdateRequest request = new UpdateRequest

          {

             Target = contact

          };

          // Add each updated record to the Multipe Request requests collection

          multipleRequest.Requests.Add(request);

       }

    }

}


Finally after making the updates to each record, we will call the Execute method on the ExecuteMultipleRequest class to retrieve the responses of all the updates.
We can then loop through the responses to verify that each record update was either successful or failed.

// Execute the multiple requests

ExecuteMultipleResponse multipleResponse = (ExecuteMultipleResponse)CRMHelper.xrm5.Execute(multipleRequest);

 

// Individual Responses and Faults

foreach (ExecuteMultipleResponseItem responseItem in multipleResponse.Responses)

{

   string fullname = ((Contact)(multipleRequest.Requests[responseItem.RequestIndex])
    .Parameters["Target"]).FullName;

   if (responseItem.Response != null)

      Console.WriteLine(String.Format("Contact {0} updates with profile information", fullname));

   else if (responseItem.Fault != null)

      Console.WriteLine(String.Format("Contact {0} could not update. The following error was
returned: {1}", fullname, responseItem.Fault.Message));

}

 

Feb 02
Choosing CRM Connection Option

Many CRM application that are written for Microsoft Dynamics CRM require to atuneticate a user with any Microsoft Dynamics CRM deployment. This sample in this article demonstrates how to connect and authenticate a user with Microsoft Dynamics CRM On-Premise or Microsoft Dynamics CRM Online (using both Windows Live Id and Office 365 credentials).

The code example below contains three methods.
A public class method that establishes the connection, and two private methods to retrieve the Authentication Credentials and retrieve the Organization Service Proxy.

The following is the list of references, variables and properties that are required for this implementation to work.

using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Client.Services;

 

public static OrganizationServiceProxy service;
private static string UserName { get; set; }
private static string Password { get; set; }

 

The ConnectToCRM creates a new OrganizationServiceProxy class that allows performing operations against all of the Microsoft Dynamics CRM environments.
The method retrieves the specified credentials and established the OrganizationServiceProxy class connection by calling the GetProxy method.

The serviceUrl contains the Uri of the CRM Services and the provider contains the type of provider that is going to be used to connect to CRM.
There are 5 options for the AuthenticationProviderType: Active Directory (1), Federation (2), Live Id (3), Online Federation (4) and None (0).

public static void ConnectToCRM(Uri serviceUrl, AuthenticationProviderType provider)
{
  
IServiceManagement<IOrganizationService> orgServiceManagement =
      
ServiceConfigurationFactory.CreateManagement<IOrganizationService>(serviceUrl);

   AuthenticationCredentials credentials = GetCredentials(provider);
  
service = GetProxy<IOrganizationService, OrganizationServiceProxy>
     
(orgServiceManagement, credentials);
  
service.EnableProxyTypes();
}

 

The GetCredentials method returns an AuthenticationCredentials class contains the credentials of the CRM user based on the environment that they are connecting to. This method shows the implementation for Active Directory, CRM Online using Windows Live Id and CRM Online using Office 365.    

private static AuthenticationCredentials GetCredentials(AuthenticationProviderType provider)
{
  
AuthenticationCredentials credentials = new AuthenticationCredentials();
  
switch (provider)
  
{
     
case AuthenticationProviderType.ActiveDirectory: // Active Directory      
        
credentials.ClientCredentials.Windows.ClientCredential =
           
new NetworkCredential(UserName, Password);
        
break;
     
case AuthenticationProviderType.LiveId: // CRM Online using Live Id             
         credentials.ClientCredentials.UserName.UserName = UserName;

         credentials.ClientCredentials.UserName.Password = Password;
        
credentials.SupportingCredentials = new AuthenticationCredentials();
         credentials.SupportingCredentials.ClientCredentials =
 
            Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();

         break;
     
case AuthenticationProviderType.OnlineFederation: // CRM Online using Office 365
         
credentials.ClientCredentials.UserName.UserName = UserName;
         credentials.ClientCredentials.UserName.Password = Password;
        
break;
     
default:
        
credentials.ClientCredentials.UserName.UserName = UserName;
         credentials.ClientCredentials.UserName.Password = Password;
        
break;
   }
   return credentials;
}

 

The following is a generic method that is used to obtain the discovery and organization service proxy.
The TService parameter is used to set the IDiscoveryService or IOrganizationService type to request the resepective service proxy instance.
The method will finally return either the DiscoveryServiceProxy or the OrganizationServiceProxy based on the TService type.

private static TProxy GetProxy<TService, TProxy>
(IServiceManagement<TService> serviceManagement,
AuthenticationCredentials authCredentials)
where TService : class           
where TProxy : ServiceProxy<TService>
{
  
Type classType = typeof(TProxy);
  
// Obtain service proxy for Windows LiveId and Office 365 environments. 
  
if (serviceManagement.AuthenticationType != AuthenticationProviderType.ActiveDirectory)
  
{
     
AuthenticationCredentials tokenCredentials = serviceManagement.Authenticate(authCredentials);
     
return (TProxy)classType
        
.GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
        
.Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
   }

// Obtain service proxy for ActiveDirectory environment.         
  
return (TProxy)classType
  
.GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
  
.Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
}

 
Once the connection to Microsoft Dynamics CRM is established, you can call any of the CRM WCF Service methods calls.
This example was created using the CRM 2011 SDK version 5.0.13 (published 1/7/2013).

Jan 15
CRM to Web Form (Internet Lead Capture) is Microsoft Platform Ready

Our CRM to Web Form 2011 is not Microsoft Platform Ready for Windows 2008 R2 and Microsoft Dynamics CRM.

CRM to Web Form provides the ability for uses to design forms in CRM and publish them to an asp.net or SharePoint web site.
The application provides customization capabilities of different areas of the page.

CRM to Web Form 2011 is available for On-Premise deployment or CRM Online.

Features include:

  • Use of CRM Form Designer
  • Unlimited number of Forms Per Entity
  • Unlimited number of Entities
  • Support for System and Custom Entities
  • Support for ASP.NET Web Forms
  • Support for SharePoint 2010 and SharePoint 2013
  • Custom Page Layout
  • Support for default field values and field Validation
  • Support for multiple types of fields
  • Customizable Css Classes
  • No Code Required

Microsoft Platform Ready 

Jan 10
CRM to Exchange Sync 2.0 is Microsoft Platform Ready

We have just released our latest version of the CRM to Exchange Synchronization application.

The CRM to Exchange Sync app provides the ability to synchronize between CRM marketing lists and Exchange Distribution Groups.
The application retrieves all the members of a marketing list, either static or dynamic and add the new distribution group members in exchange.

Existing members can be modified with updated information from Microsoft Dynamics CRM.

The new version includes the following features:

  • Integration with Microsoft Dynamics CRM Online
  • Asynchronous Processing (as a Windows Service) of the Exchange Sync app
  • Support for synchronizing with any CRM Contact related entity

In addition, the application has passed the Microsoft Platform Ready Windows 2008 Server R2 and Dynamics CRM 2011 Tests.

The solution is available as a trial for 30 days.

Jan 03
CRM to Web Form (Internet Lead Capture) version 1.0 released

Brite Global has just released the first version of its Internet Lead Capture software.

Internet Lead capture enables customer to easily and quickly design forms within CRM and publish them on their web site.

Some of the feature include:

  • Use of the CRM form designer
  • Support for both system and custom entities
  • Support for asp.net web sites
  • Personalization of web form to include you own image, title, button and more.
  • Customizable CSS classes

We are currently working on some additional features of the product, all which will be available before the February 15 cancellation of Microsoft Dynamics CRM Online Internet Lead Capture service.

For more information, visit the CRM to Web Form page on our web site or watch the demo video on YouTube.

Dec 19
Changing Settings for Activity Party in Email Form

We have all used the email form in CRM 2011, however many times we might want to customize the activity party fields (to, cc, bcc), so that we can restricted the email enabled entities.
The image below displays the default entities that will be shown when we click on the activity party lookup button. Notice that custom email enabled entities will also be shown on this list.

In order to modify the entities, we will have to set the lookuptypes, lookuptypeicons and lookuptypename attributes of the activity party field as shown in the code below.
We can also set the defaulttype that will display when we open the lookup dialog window.

After the customizations have been published, only the required entities will be shown on the when the activity party lookup control is opened.
You will notice that the License custom entity is the default entity as set in the defaulttype attribute.

In order to select multiple results, you will have to set the lookupstyle attribute to "multi" as well.

Note that the above code might have to be modified for other supported browsers after applying CRM 2011 UR12.

Dec 13
Implementing Field Security in CRM 2011

Field Security in CRM is globally scoped which means that it will apply to all client types and whatever the position of the user is in business unit hierarchy.
Field Security is always enabled in any type of access to the CRM client such as Reports, Quick Find, Offline Access, Filtered Views, Auditing, SDK, etc...

Step 1 – Enabling fields for Field Security

Fields are enabled for security through the fields security form.
In order to enable a field for security we set the value on the Field Customization form to enabled.


This will place a key symbol next to the field on the CRM form as shown in the picture below.

Step 2 – Setting Field Security Profiles

The Field Security Profile defines the permissions that users and teams, also referred as Security Principals are going to have on particular fields.
There are three access right levels that can be granted on each security field: Read, Create and Update.

The field permissions on each field applies to all the security principals that are listed in the security profile. These permissions operate independently.
This means, for example, that you can grant Update permissions without Read permission.

In the Field Security Profiles section, in the Settings -> Administration area, we can create new field security profiles.
We specify the name and a description for the new security profile that we are going to create and specify the names of the users and/or teams that belong to the security profile.

Finally we specify the field permissions to specify what kind of permissions the users and teams have on that field that we require by selecting the field and clicking the Edit toolbar button:

System Administrator Field Security Profile

The System Administrator Field Security Profile is added to the system by default, with every field's permissions set to Yes for each of the security-enabled fields.
This profile cannot be deleted, and is automatically populated with any user/team that has the System Administrator Security Role.

The System Administrator Field Security Profile makes sure that there is always at least one user with permissions to modify field security.

Dec 07
One-Way Sync between Outlook and CRM

We recently got a request from a client that wanted to prevent modifications of Contacts from the Outlook Client back to CRM.
We went back and forth trying to implement this with security roles and other options, but none of the solutions were perfect.

Finally we decided to implement this using Plugins.
The solution was to allow Outlook to make the changes, but as soon as they are made, revert them back to their original values.

There were four parts to the solution:

Step 1 - Creation of a temporary entity to hold the values that are modified by the Outlook Contact record.

The first step is to create a holding tank or staging entity that will store the changes that were performed to the Outlook Entity.
This is a simple entity that will have the name of the field, the original value and the changed value. Those values will be updated in the entity by the Contact Update Pre-Operation Plugin.

The screenshot below shows the Sync record portion of with the modifications that were made in an Outlook record.

Step 2 – Creation of a revision or timestamp field in the CRM Contact record.

The next step is to create a field in the CRM Contact entity that will always be modified.
You can create a revision field or a timestamp/date time field that you will update in JavaScript when the form is being loaded or saved.

If you use a revision field, make sure to increment the value of the field before the form is saved.
This will tell the plugin there were changes in the form that were called from the CRM form and not from Outlook.

If you use other methods to make updates to your CRM Contact form besides the CRM Form and Outlook, then make sure to update the code in those CRM Update method calls to also increment the revision or modify the timestamp.

Step 3 – Creation of a Contact Update Pre-Operation Plugin Message to store the changes done by Outlook

The next step is the creation of the first Plugin Message. This message will be called before the changes are saved to the Outlook Contact record.
In this step we will first check if the Plugin was called from CRM or Outlook.
If it was called from CRM, we will not do any processing, however if it was called from Outlook we will start processing the changes.

The GetInputParams method will retrieve the existing field values of the contact record in CRM.
It will then loop through all of the fields that were modified, and for each field that was modified create a SyncField in CRM with the name of the field, the existing value and the requested value.

Our application also sends an email out to an administrator that these changes were required.

Step 4 – Creation of a Contact Update Post-Operation Plugin Message to revert the values back

The last step retrieves the records that were temporarily stored in the SyncFields entity and modifies the Contact entity with the values that existed before the changes that were initiated from Outlook.

Step 5 – Optional approval process

Step 5 is an optional state that will call a Plugin on the Outlook Sync entity that will accept the changes that originated from Outlook.

Dec 04
CRM Forms and Silverlight Web Resource Integration

When developing a Silverlight Web Resource that has to be added to the CRM form, many time we require to pass data back and forth between the two.

The first step, is that we need to add a couple of classes to the Silverlight application that will allow us to communicate with CRM.
These two classes are the silverlightutility.cs and silverlightextensionmethods.cs, which can be located in the SDK under samplecode\cs\silverlight\soapforsilverlight\soapforsilverlightsample folder.

This article will demonstrate how to communicate between the applications.

The first example shows how to retrieve the first name and the last name fields from the contact entity from.
Notice the use of the dynamic object, and the two methods for retrieving the form data.
A reference to the System.Windows.Browser has to be added to class.

The next example will show how to call a Jscript function on the form.
The HtmlPage.Window.Invoke method accepts two parameters: the name of the Jscript method and the params collection of object data types.

The last example will demonstrate how to use the Retrieve method of the IOrganizationService to retrieve data from another entity.
Calling the service methods of the IOrganizationService are performed asynchronously, which requires also the creation of a callback method.
The code examples below will call the retrieve method on the account entity and then in the callback method will assign the retrieved values to the string data type.

You can also use the IOrganizationService to call other web methods such as RetrieveMultiple, Create, Update, etc…

1 - 10Next

 About this blog

Welcome to the  Brite Global Blog. Here you will find content related to new and existing technologies, company, news and events.
Powered By SharePoint 2013