Friday, January 28, 2011

CRM 2011 SDK - Set owner of record to inactive user

Can you programmatically set the owner of a record in CRM to an inactive user?  Yes, but see below for more information.

I'm working on a data migration project involving Salesforce.com to Dynamics CRM 2011 Online. The source data includes thousands of records that are assigned to inactive Salesforce.com users. Our client wants to maintain the owners in CRM but also wants the users who are inactive in Salesforce to be inactive in CRM.

That brought up the question: "Can you programmatically set the owner of a record in CRM to an inactive user?". Yes (see sample code below). The only requirement is that each user (systemuser) must have at least one security role assigned, otherwise the CRM proxy service will throw a FaultException with the message "SecLib::RetrievePrivilegeForUser failed - no roles are assigned to user.".

Here's the code I used to test this scenario:
Guid ownerIdForInactiveUser = new Guid("1412c4da-fb2a-e011-8526-1cc1def8ea35");

string accountName = "Tim Test 1";
Entity accountEntity = new Entity("account");
accountEntity["name"] = accountName;
accountEntity.Attributes.Add("ownerid", new EntityReference("systemuser", ownerIdForInactiveUser));
try
{
   crmService.Create(accountEntity);
}
catch (FaultException ex)
{
   Console.WriteLine(ex.ToString());
}
Cheers,
-Tim

Thursday, January 20, 2011

CRM 2011 SDK: WinOpportunityRequest and ArgumentNullException

In several of the Dynamics CRM 2011 SDK sample C# files, you'll see this comment and code line:

// This statement is required to enable early-bound type support.
_serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());


You might think that if you're writing late-bound code, like I was doing earlier today for a data migration project, that you wouldn't need that line of code. That's true if all you're doing is creating Entity instances, setting attributes, and executing CRUD operations (e.g., _serviceProxy.Update(myEntity)).

What I learned the hard way today is that you need that line of code if you're calling the Execute method for the service proxy with an instance of WinOpportunityRequest, LoseOpportunityRequest, and the other "Request" classes. If you don't run that code then you'll probably run into the ArgumentNullException after invoking Execute on the service proxy.

In hindsight, the "Opportunity" part of the name "WinOpportunityRequest" should've led me to think "maybe that's an early-bound class and therefore I need to set that ProxyTypesBehavior thing I read about". But I was convinced I was operating late-bound only. Apparently not. Another lesson learned.

Wednesday, January 19, 2011

CRM 2011: Running JScript Code Interactively in IE 8

While working on client-side code in Dynamics CRM, it's often faster to write and test the code incrementally within the context of a a "live" form, so that adjustments can be made quickly. Then, once a block of code is working, most of it can be moved to a code library to be further tested in CRM.

This article shows how to run jscript (javascript) code within an account form to format a phone number. The process utilizes the "Run Script" features in the Developer Tools utility that's included with Internet Explorer 8. The code assumes you are working in Dynamics CRM 2011.

Step 1: Load the CRM form upon which you want to run/test JScript code. For this example, load the Account form since the value of the “telephone1” field will be reformatted later in the example.

Step 2: Enter an unformatted phone number in the Main Phone (telephone1) field.  Example: 4255551212

Step 3: In IE, press F12 to load the Developer Tools window.

Step 4: Click Script and then click the Multi Line Mode button.

Step 5: Run the script shown below.
// Reference the main form window (iframe)

var oWindow = document.getElementById("contentIFrame").contentWindow;

// Reference the field with the phone number to format.
var oField = oWindow.Xrm.Page.data.entity.attributes.get("telephone1");

// Remove any non-numeric characters from the field's data.
var sTmp = oField.getValue().replace(/[^0-9]/g, "");

// If the number has a valid length, format the number.
switch (sTmp.length)
{
case "4255551212".length:
  oField.setValue("(" + sTmp.substr(0, 3) + ") " + sTmp.substr(3, 3) + "-" + sTmp.substr(6, 4));
  break;
case "5551212".length:
  oField.setValue(sTmp.substr(0, 3) + "-" + sTmp.substr(3, 4));
  break;
}
Step 6: View the Main Phone field again in the account form. The value should be formatted as (nnn) nnn-nnnn.

Wednesday, December 22, 2010

Show attribute schema names within form editor

Maybe it's just me, but occasionally I find value in viewing attribute schema names in context of a form. This capability was on my wish list for Dynamics CRM 2011 but it didn't make the cut. Fortunately, you can run the JavaScript code I provided below to do just that.

You can execute this script and any other JavaScript code using the built-in "Developer Tools" in IE8 or by using IE WebDeveloper. First, load the form editor view (CRM displays the form editor UI in its own window). Then press Ctrl+N to open the editor in a window that allows you to get to the IE toolbar. Either press F12 (IE 8 only) or use IE WebDeveloper. Run the script in the interactive script window that's provided in each tool.
document.getElementsByClassName = function(cl,doc) {

  var retnode = [];
  var myclass = new RegExp('\\b'+cl+'\\b');
  var elem = doc.getElementsByTagName('*');
  for (var i = 0; i < elem.length; i++) {
    var classes = elem[i].className;
    if (myclass.test(classes)) retnode.push(elem[i]);
  }
  return retnode;
};
var doc = document.getElementById("contentIFrame").contentWindow.document;
var crmFormFields = document.getElementsByClassName("field",doc);
var crmReadOnlyFields = document.getElementsByClassName("rofield",doc);
if (crmReadOnlyFields.length > 0) {
  crmFormFields = crmFormFields.concat(crmReadOnlyFields);
}
var crmFieldId;
var crmFormField;
for (var i = 0; i < crmFormFields.length; i++) {
  crmFormField = crmFormFields[i];
  if (crmFormField.parentNode.parentNode.parentNode.parentNode.name) {
    crmFieldId = crmFormField.parentNode.parentNode.parentNode.parentNode.name;
    crmFormField.innerText = crmFieldId;
    crmFormField.style.color = "#000000";
  }
}
Here's a snapshot of part of the Account form. After running the script, the display name for each attribute is replaced with the schema name.

 

Thursday, October 14, 2010

Party Foul

Oh no! What's this?!?  Failure: contact_activity_parties: Cascade link type 'NoCascade' is invalid for Delete.


I ran into that error today but found a way around it. Here's the scoop.

I fired up a VPC with Dynamics CRM 4.0 Rollup 13 today and added 21 attributes to the Contact entity, which was previously unmodified. I then exported the Contact entity to XML and send the resulting zip file to someone I work with. He has the main VPC and needed some help. Anyway, he attempted to import the Contact entity into another CRM Rollup 13 instance and got the error I mentioned above.

After calling each other crazy and demanding proof that we were both running Rollup 13 (we were... not crazy, but running rollup 13, well maybe both), I exported the Contact entity and immediately re-imported the zip file. Bam! Same error... on the same CRM instance! Grrrrr.

The "solution"?  I removed the node "<EntityRelationship Name="contact_activity_parties">" from the Contact XML, saved the file, and wouldn't you know it, CRM imported that version of the customizations file just fine.

I'm sure, I have to believe, okay I hope (but not holding my breath) that Microsoft has made customization import/export rock solid between rollups in Dynamics CRM 2011. I can understand that moving customizations between different rollups is hard for Microsoft to get right but exporting and re-importing on the same server, within only 38 seconds lapsing between the time the zip file plopped onto C: to when I optimistically clicked the Import button -- for that not to work is, well, causing me to write this blog post instead of working. So with that, onward to the next challenge.

Friday, September 10, 2010

Dynamics CRM 2011 Beta SDK Greatest Hits

Here are some articles, notes, and tidbits I've found so far in the Dynamics CRM 2011 SDK that are particularly cool, as compared to the now "old school" version 4.0 of the product.
  • Azure Integration: In simple terms, the CRM async service can send messages to a queue in Azure to process. That will make this 4.0 application better because I can now perform integration tasks from CRM changes rather than using a polling service.
  • Multiple Forms for an Entity: You can define more than one main form for each entity. Use multiple forms to create forms that are customized to specific roles or tasks in the organization.
  • REST Endpoint: In 4.0, writing client-side code in SOAP is not exactly fun or easy. In 2011, you can replace a lot of that code with REST-based calls using JQuery or other jscript libraries.
  • Goals!: Goal Management enables you to set the sales, marketing or other business goals for your organization and measure the results against the targets.
  • Silverlight Samples: It's great to see sample code in the SDK for interacting with Silverlight applications. Of course, David Yack was way ahead on this but this adds to the cool factor in the SDK.
  • Data Auditing: Audigint is built in and can be enabled at the organization, entity, and attribute levels.
  • Custom Activity Types: You can create your own activity types to track customer interactions that go beyond the built-in phone, letter, e-mail, task, etc. For example, if you business has a customer portal for service incidents, you might want to track interactions in the portal as a custom activity type.
  • Web Resources: Web Resources are 'virtual files' that are stored in the CRM database and may be retrieved using a unique URL address. Web Resources can be used in Form customizations, Sitemap or the application ribbon.
  • Sandbox for plug-ins: CRM Online will benefit from the ability to run plug-ins in an isolated environment. In this environment, also known as a sandbox, a plug-in can make use of the full power of the CRM SDK to access the Web services.
  • Entity Connections: A person I worked with at a large Northwest company has a brother who I run into often while hiking in the Cascades. He works for a subsidiary of the larger company. Now, in CRM 2011, I can connect those contacts in ways that helps me and others at Altriva know how they're related (or conneted) to each other.
  • PowerShell Cmdlets: The Beta SDK has placeholders in the documentation for instructions on how to use PowerShell to help with deployment-related tasks.
  • Solutions: Solutions are how customizers and developers author, package and maintain a single unit of software that extends Microsoft Dynamics CRM.
  • Recurring Appointments: Create recurring appointments with flexible intervals/patterns.
One feature that I'm hoping Microsoft will hurry and add is one that can generated a unique number. This is a common customization that we add for our clients but it really should be built in to the product.

Monday, August 23, 2010

Azure / CRM app won't deploy - Initializing, Busy, Stopping

I made a simple code change to an Azure WorkerRole service today. Before deploying the app, I noticed that the folder where my code lived on my machine didn't match up with source control so I did a little readjusting of folders. No big deal, I thought. The application compiled fine and ran on my local dev fabric.

After deploying the updated Azure service, the deployment screen showed Initializing, then Busy, followed by Stopping... and then went back to Initializing, Busy, etc. It was stuck in a loop. I read something about this in the past and knew that it related to invalid DLL references, invalid configuration or a number of other things.

After convincing myself that my code change was working and  had proper exception handling just in case, I put all the pieces of the application back in their previously known working locations. Voila! The application deployed to Azure fine.

What happened is that Visual Studio started referencing 32-bit versions of the CRM SDK assemblies (microsoft.crm.sdk.dll and microsoft.crm.sdktypeproxy.dll) when I moved the application to different folders -- it could no longer find the 64-bit files I referenced previously. So when I deployed the application the 32-bit CRM assemblies went along up to Azure... but Azure only runs with 64-bit assemblies!

I was punished once again by good intentions. But at least I can add this troubleshooting lesson to my list for future reference.