CRM Blog

January 2009 - Posts

Example of Dynamic Entity Retrieval
by Danny Varghese 01.31.09

Comments    1 Comment(s)

There have been numerous requests on other blogs about sample code to on how to retrieve entities in CRM.  One way is to use the CRM web service to retrieve business entities, however by doing so, you're only limited to out-of-the-box entities with system attributes.  To retrieve anything more "dynamic," you'll have to employ other methods.  Please remember that in order to retrieve any record, you must have the proper permissions on that entity.

 

Below is a code example of how to retrieve a record with an id using dynamic entity retrieve:

 

 

 public DynamicEntity RetrieveEntity()

{

            //variable initialization    

            TargetRetrieveDynamic target = new TargetRetrieveDynamic();        

            RetrieveRequest retrieveRequest = new RetrieveRequest();           

            RetrieveResponse retrieveResponse = null;                                      

DynamicEntity entity = null;                                     

 

            target.EntityName = <name of entity here>

            target.EntityId = <id of entity here>

 

            //initialize request parameters

            retrieveRequest.ColumnSet = new AllColumns();

            retrieveRequest.ReturnDynamicEntities = true;

            retrieveRequest.Target = target;

 

            //build the response object

            retrieveResponse = (RetrieveResponse)GetCrmService().Execute(retrieveRequest);

 

            //retrieve the service order item from the response

            entity = (DynamicEntity)retrieveResponse.BusinessEntity;

 

            return entity;

}

 

 

The above example is a simple one, but the example below retrieves all contacts that have an account id = some id, and also retrieve the records with only a certain attributes.  This is probably a more robust example encompassing many retrieval options:

 

private ArrayList RetrieveMultipleContacts(ICrmService crmService, Guid parentAccountId)

{

//variable initialization

ConditionExpression condition = new ConditionBLOCKED EXPRESSION;

FilterExpression filter = new FilterBLOCKED EXPRESSION;

QueryExpression query = new QueryBLOCKED EXPRESSION;

RetrieveMultipleRequest request = new RetrieveMultipleRequest();

ColumnSet cols = new ColumnSet();

RetrieveMultipleResponse response = null;

ArrayList contacts = new ArrayList();

 

//Set the condition for retrieval

condition.AttributeName = "parentcustomerid";

condition.Operator = ConditionOperator.Equal;

condition.Values = new string[] { parentAccountId.ToString() };

 

//Set the properties of the filter.

filter.FilterOperator = LogicalOperator.And;

filter.AddCondition(condition);

 

//Set the attributes needed to be returned.  NOTE: The CRM Sdk has an erroneous example

//of how to set the attributes for retrieval.

cols.Attributes.Add("address1_line1");

cols.Attributes.Add("address1_line2");

cols.Attributes.Add("address1_line3");

cols.Attributes.Add("address1_city");

cols.Attributes.Add("address1_stateorprovince");

cols.Attributes.Add("address1_postalcode");

cols.Attributes.Add("address1_country");

cols.Attributes.Add("telephone1");

cols.Attributes.Add("fax");

 

//Set the properties of the QueryExpression object.

query.EntityName = EntityName.contact.ToString();

query.ColumnSet = cols;

query.Criteria = filter;

 

//Set the query for the request and set the flag to return

//dynamic entities

request.Query = query;

 

//retrieve the contacts

response = (RetrieveMultipleResponse)crmService.Execute(request);

 

foreach (BusinessEntity cont in response.BusinessEntityCollection.BusinessEntities)

{

contacts.Add(cont);

}

 

return contacts;

}

 

I hope these examples help someone, happy coding!

Filed under:
Open vs. Scheduled Appointments In CRM
by Danny Varghese 01.23.09

Comments    No Comments

In CRM, when creating appointments, you can set the status to Open or Scheduled.  But why would a user set the status to one or the other?

 

According to the SDK, the status and state codes are different:

 

 

 

For CRM Outlook users, the only real difference seems to be the scheduling.  When other users look at your calendar during this time period, if the appointment was marked Open, the time block will be marked as "tentative."  If the appointment was marked Scheduled, the time will show up as "busy" in Outlook.

Filed under:
Using CRM Workflow To Create Audit Trail
by Danny Varghese 01.20.09

Comments    No Comments

 

There's an excellent post on the MSDN CRM blog on how to create an audit trail using the CRM 4.0 workflow.  I've had numerous customer requests for an audit trail of entities when a field changes.  Clients want to know when certain fields change, and who made the change. 

 

The MSDN post gives a great example of using out of the box CRM workflow functionality to meet their needs: http://blogs.msdn.com/crm/archive/2008/04/10/using-workflow-to-maintain-an-audit-log.aspx.

Infinite Loop In CRM Workflow Custom Assembly
by Danny Varghese 01.19.09

Comments    2 Comment(s)

 

Business Requirement

I recently had a requirement where if an account's address was updated, all associated contact's addresses needed to be updated as well.  Likewise, if a contact gets re-associated to another account, i.e. the parentcustomerid field gets changed, then update that contact's address.

 

Initial Development

I thought we could use a CRM custom workflow activity to handle this because it gives the business user the ability to configure the workflow.   So I created two separate workflows that would call a custom workflow activity assembly.  The trigger to call the account workflow was if any of the address attributes changed, and for contact was if the parentcustomerid was set/changed.

 

The assembly itself first checked the workflow context to see what the primary entity was (to handle being called from the account or contact workflow).  Then the required business logic was performed, and the CRM web service update was called to update the contact entity.

 

Test Results

After I registered the assembly and started unit testing, it looked as if everything worked. Then looking at the history of workflows for the test contact record, I noticed about six entries for the workflow I just configured.  Then I used a VPC and tested the assembly by using Visual Studio debugger, attaching it to the CRM Asynchronous  Service process,  and found that there was an infinite loop occurring.

 

When the contact record was re-associated to another account, the workflow kicked off and executed the custom assembly.  Within the code, it set only the address properties on that record and then called the CRM service update method.  Right after that update was made, a new workflow instance was called again.  To make sure, I commented out the update call in the code and…no more loops!

 

Final Thoughts

Some technologies have flags for attributes to determine if that particular attribute has been updated or not.  When the CRM web service update was called, even though I only set the address fields, it seems to "flag" that all attributes have been updated.  Either that, or the workflow conditions were never checked. 

 

I even tried to add some sort of check to make sure even if the workflow was called the code wasn't executed.  However, unlike plug-ins, workflows don't have functionality to check the values before and after an update.  I also tried putting a global counter to update after the first run, and check if the method was called again.  However, the entire workflow was called again, which created another instance of the class, thus the counter idea didn't work.

 

Solution

I finally ended up using a plug-in, which you can configure to run asynchronously if you heart desires.  In the future, I now know that a workflow should not be setup to call a custom assembly that updates that same record.  The CRM web service update will cause infinite loops, and is better handled via a plug-in.

Filed under:
CRM WebService Error: Only one usage of each socket address (protocol/network address/port) is normally permitted
by Luke Simpson 01.15.09

Comments    7 Comment(s)

When performing a data integration or migration into CRM, it is very common to create a .Net application that transforms the data, then pushes the records into CRM using the WebServices.  At times, however, the load of data being pushed to IIS can be more than is acceptable to the default settings in an IIS implementation.  At these high load times, the server might post an error stating "Only one usage of each socket address (protocol/network address/port) is normally permitted (typically under load)."

What is happening, is that connections are being repeatedly opened and closed on the webserver.  When a connection is closed, the connection goes into a TIME_WAIT state for 240 seconds.  This is the default setting.  In this case, the IP being used is typically fixed, which means that the variable is the local port.  By default ports 1024-5000 are available to be used, which means that using default setting you have approximately 4000 ports to be used during a 4 minute span (240 seconds).  So if your code is making more than 16 webservice calls per second, you will exhaust all of the available ports!

 To fix this problem, you can make 2 different registry changes on the CRM Application Server.

  1. Increase the dynamic port range.  As stated above, the default is 5000 but this can be raised up to 65534.
    • Using Regedit, navigate to  HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\MaxUserPort (if this key does not exist, create it as DWORD value)
    • Set the value to 65534, or a value of your choice
  2. Reduce the amount of time that the connection is in a TIME_WAIT state.
    • Using Regedit, navigate to  HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\TCPTimedWaitDelay (if this key does not exist, create it as DWORD value)
    • Set the value to 30

 By performing the actions above, you are allowing the server to use a far larger number of available ports, and you also allow the server to recycle them faster.  Problem solved!
Filed under:
IE Enhanced Security Configuration interferes with CRM
by Luke Simpson 01.08.09

Comments    No Comments

If you are having problems selecting colums to edit/remove from a view in CRM, then the Internet Explorer Enhanced Security Configuration may be the culprit.  In IE 6 it is called Internet Security Configuration.  A fix that I found worked and you may want to consider, is to go to Add/Remove Programs on the CRM server, select Add/Remove Windows Components and uninstall the Enhanced Security Configuration.  After it has been uninstalled, perform an IIS reset (sometimes you need to reboot the server) and you should be good to go, however removing this could have other security related consequences and should be reviewed thoroughly.

Filed under:
Formatting Mail Merge fields in CRM 4.0 Mail Merge
by Zahara Hirani 01.05.09

Comments    No Comments

 

Recently, I had to do some custom formatting for mail merge documents in CRM 4.0 and here are a few format examples:

Formatting a Date:
         {MERGEFIELD "MyDate" \@ "M/d/yyyy" \*MERGEFORMAT}

If you just wanted to add the current date when creating the document:
         {DATE  \@ "M/d/yyyy"}

Formatting a number as a currency value:
         {MERGEFIELD "MyAmount" \# "$0.00" \*MERGEFORMAT}

Formatting a number as a percentage value:
         {MERGEFIELD "MyPercent" *100  \# "0%" \*MERGEFORMAT}

Formatting a number with a specific format:
         {MERGEFIELD "MyAccountNumber" \# "00 00 000" \*MERGEFORMAT}

Enjoy!!

Filed under:
Creating a Differencing Disk For CRM VPC Images
by Danny Varghese 01.02.09

Comments    No Comments

 Intro

    Ever since I started learning about and developing for Microsoft CRM, I've used VPC (virtual pc) images to develop and test customizations, workflows, security roles, etc.  Often times I would have to copy the virtual hard drive multiple times for multiple clients.

     

    Differencing disks allow you to create a new disk off of a parent disk, but going forward, all changes made to that disk are saved to the new disk.  This will allow you to have multiple virtual machines setup, but only using one parent virtual hard drive. 

     

    Steps To Create Differencing Disk

    1. Create Virtual Hard using the wizard via the Virtual PC Console

 

 

    1. Click Next | Create New Virtual Disk | A Virtual Hard Disk.
    2. Choose a location for where you want this to be stored.
    3. Choose the Differencing Disk option.
  •  
  •  

    1. Select the parent virtual hard drive | Click Finish
    2. Next to create a virtual machine use the virtual machine wizard

     

     

     

    1. Click Next | Create Virtual Machine | Next
    2. Browse to a location to save the virtual machine
    3. Set the operating system | Set the memory required
    4. Select an existing virtual hard disk | Next
    5. Browse and select the virtual hard disk created in steps (1) - (5).
    6. Click Finish

     

    You have now created a differencing disk!

Filed under: