Thursday, May 31, 2007

CRM 3.0: Converting DynamicEntity to a Core Entity

Microsoft was very kind. They gave the us the power of the DynamicEntity. Very handy. They also give us the hard-typed "core" entity objects.

In the case of callouts core entities are not used and only dynamic entities are passed to the callout functions. Working with DynamicEntities though can be a pain, especially when it comes to changing one field and updating the record back in CRM. Since there is no direct access to a specific field, if you want to update a field you need to step through each of the Properties on the DynamicEntity until you find the one you want. Not real efficient if you ask me.

So, this is where having a hard-typed "core" entity comes in handy. But how do you convert? EASY! Well, sorta easy. You see, MS provided a great little code snippet in the CRM SDK for doing such a conversion. It's right here.

However, there is one little problem with this.

So I started to play with this by creating a real simple test app and then retrieving an account DynamicEntity:

tempService.Url = @"http://danubecrm:5555/MSCRMServices/2006/crmservice.asmx";
tempService.Credentials = new System.Net.NetworkCredential("administrator","pass@word1","crmdomain");
RetrieveRequest getEntity = new RetrieveRequest();
TargetRetrieveDynamic target = new TargetRetrieveDynamic();
target.EntityId = new Guid("f0705cff-1e0f-dc11-99e2-0003ff2689b7");
target.EntityName = "account";
getEntity.Target = target;
getEntity.ColumnSet = new AllColumns();
getEntity.ReturnDynamicEntities = true;
RetrieveResponse response = (RetrieveResponse) tempService.Execute(getEntity);
DynamicEntity tempDynamicEntity = (DynamicEntity)response.BusinessEntity;

And then I fed it into the Convert function. CRASH!

It turns out that the DynamicEntity comes back with the StateCode field being a "StateProperty" type. However, on the account object the StateCode field is an AccountStateInfo type. When the reflection methods tried to write the String value that came from the StateProperty.Value, it crashed cause there is no implicit converstion between a String and a AccountState object.

So I modified the code conversion routines to ignore this field. I'm sure there is a better solution but right now there is a project to get done and I don't need to know the StateCode of the account to get it done.

Monday, May 14, 2007

CRM 3.0: Using QueryExpressionHelper to get a Contact's GUID

Here is an example of how to use QueryExpressionHelp to get a Contact's GUID.


QueryExpressionHelper queryHelper = new QueryExpressionHelper(EntityName.contact);
queryHelper.Columns.AddColumn("contactid");
queryHelper.Criteria.Conditions.AddCondition("FieldNameFromEntity", ConditionOperator.Equal, thisIsTheParameter);
queryHelper.Criteria.FilterOperator = LogicalOperator.And;
BusinessEntityCollection coll = service.RetrieveMultiple(queryHelper.Query);
contact user = (contact)coll.BusinessEntities[0];
Guid syscoGuid = user.contactid.Value.ToString();

Wednesday, May 9, 2007

The Importance of Proper User Removal

Recently I wrote an integration using SSIS and the CRM web services that created and updated accounts and contacts in CRM. However, there were some accounts which CRM refused to update returning the following error:

0x80040204 Invalid user auth




Updating the records through IE posed no problems.

Searching the web showed that this error only came up when using impersonation, which I wasn't doing.

After reviewing the data it was determined that the owner of the records had been deleted from Active Directory.

To fix this, all we needed to do was reassign the accounts to a different user and all worked well from then on.

So, it's very important that when users leave the company that their accounts in AD don't get deleted. If this is a procedural requirement for the client, then make sure you re-assign any accounts. This should be done naturally in the process of a user leaving the company but can sometimes get missed.

-M

Thursday, May 3, 2007

Hiding and Disabling CRM fields with Javascript

I always forget the syntax for hiding and disabling fields in CRM. Below are some common examples:

//hide contract and contract line fields
crmForm.all.contractid_d.style.visibility = 'hidden';
crmForm.all.contractdetailid_d.style.visibility = 'hidden';


//hide a tab
crmForm.all.tab3Tab.visibility = "hidden";

//disable lookup fields
var oField = crmForm.all.SOME_FIELD_ID;
oField.Disabled = !oField.Disabled;


//disable radio button field
crmForm.all.new_inboundoutbound.disabled = true;

//disable datetime field
if(crmForm.FormType!=4)
{
//disable data field
var oField = crmForm.all.new_resolutiondate;
oField.Disabled = !oField.Disabled;
}

Export CRM form field names

I recently had to export all the CRM form field names for a particular entity for a data mapping exercise. I needed the actual display names instead of the attribute schema names. I had to do all this through the front-end application since I didn't have access to the database. This is what I did:
  1. Open Advanced Find and create a query (against the Contact entity in this case).
  2. Use the Edit Columns feature and add all available fields by going to "Add Columns" and choose the "Select All" checkbox which selects every field.
  3. Run the query and export the data to Excel.
  4. Open the Excel spreadsheet and copy the first row which contains all the column names (the CRM fields).
  5. On a new spreadsheet go to the Edit menu and choose "Paste Special". On the pop-up menu that appears check off the "Transpose" field. This will convert the columns to rows. Voila!

Wednesday, May 2, 2007

Calling a Workflow Rule from a button

Here's a handy bit of code for calling a Workflow rule from a custom button in CRM. Put the code below into the Page_Load handler of an aspx page. In this example I call the aspx page and pass an Account record GUID (accountId) which is fed into the workflow rule.

// CRM Service Setup
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.Url = "http://server/mscrmservices/2006/crmservice.asmx";


// Setup the request
string accountId;
accountId = Request.QueryString["accountId"];
ExecuteWFProcessRequest request = new ExecuteWFProcessRequest();


// Triggers Workflow process
request.ProcessId = new Guid("{E4206735-0379-4DE5-A453-AC7A7DA1462B}");
request.EntityMoniker = new Moniker();
request.EntityMoniker.Id = new Guid(accountId);
request.EntityMoniker.Name = EntityName.account.ToString();


// Execute the request
ExecuteWFProcessResponse response = (ExecuteWFProcessResponse) service.Execute(request);