Knowledge found and lost while working with Microsoft Dynamics CRM
RSS icon Home icon
  • Using CRM web services in client-side JavaScript

    Posted on March 31st, 2007 mitch Print Print No comments

    I was working on a project for an associate this morning and needed to generate a SOAP message that would query CRM using the web service API from JavaScript.  After Googling around a bit, I ran into one of the most useful tools I've seen in a while.

    My friend and fellow CRM MVP Michael Höhne has a little utility that will generate a complete set of JavaScript that will not only query the CRM database, but he also includes code to execute the SOAP message and return it's result set as an XML document.

    Further Googling found an article on A List Apart that enabled me to extract a value for a node within the XML result set.  I modified it slightly to add some error correction.  Place the following code at the bottom of the JavaScript generated by the default sample in Michael's utility:

     

    var myValue = getNodeValue(resultXml, 'emailaddress1');
    
    alert(myValue);
    
    function getNodeValue(tree, el)
    {
       var retVal = null;
       var e = null;
       e = tree.getElementsByTagName(el);
    
       if (e != null && e[0] != null)
       {
           retVal = e[0].firstChild.nodeValue;
       }
    
        return retVal;
    }

    This will parse the XML result set and display the main email address for the Account.

    Great work again Michael.

    Customization, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    2,639 views
  • Discussion Regarding CRM Data Import Strategies

    Posted on March 30th, 2007 mitch Print Print 1 comment

    I sometimes spend way more time than I should working on projects that allow me to increase my understanding and knowledge.  My current CRM installation is no different.  I have invested a great deal of non-billable time on the data import process so that I can better gauge the requirements for future projects of a similar nature.  I thought I'd post some of my insights should they prove useful to others in the CRM Community.

    Background

    This customer has a Business Operations System (BOS) written in Microsoft Access that runs their entire company. We are moving their customer data out of this system into Microsoft Dynamics CRM in order to make better use of the functionality that CRM provides.  The main operational features will remain inside of the Access application which has been modified to utilize CRM as the data provider for the customer and contact information.

    Note: My customer uses the term Customer for Account and I will that term for this article.

    Requirements

    The main task was to move the customer and contact information into CRM.  A secondary task was to provide the data back to the BOS in a manner that would not require retooling of that application or if modification was necessary, make it a minimal-cost change

    Relationships, Relationships, Relationships

    The main challenge I faced was moving from a fairly flat database schema into the highly relational CRM schema.  The BOS has two tables that store both Customer and Contact information. The two tables are linked to provide a parent-child relationship between Customers.

    Strategy

    I had to develop a plan for moving this data into CRM, creating the relationships between Customers and Contacts and Parent and Child Customers.  After much thought and more than a little trial and error, I finally arrived at a multi-step operation that allowed me to import the data then later establish the necessary relationships.

    Tools

    Instead of using the native CRM import utility or going with a commercial product like Scribe Insight, I decided to use the Bulk Import sample application that Microsoft released a few weeks ago.  I chose this route because I wanted to gain experience with the tool and to better understand its capabilities.  I have a couple of upcoming projects that will probably utilize customized versions of Bulk Import so I wanted to know what I was getting myself into.

    The tool itself if very well written and contains a variety of interesting programming techniques. I had to introduce modifications that would allow me to move additional data types not supported in the base product, but that was a fairly minor detail.

    Bulk Import supports threading so the operations it performs are actually fairly quick.  On one import, for the Contacts I think, I was using four threads and was obtaining 22+ creates per second.  This allowed me to move roughly 8,000 Customers and 8,000 Contacts into CRM in much less than an hour.

    Data Preparation

    As I mentioned in a previous article, when you import data into CRM using the CRM Web Services, you can either allow CRM to assign an ID ( GUID ) or programmatically assign it yourself as data provided during the import process.  I chose the latter approach and the following techniques:

    1) I created duplicate work tables containing data from the two BOS tables.

    2) Microsoft SQL Server provides a function called NewID() to generate a GUID. 

    3) I created columns to record the following IDs:

    a) Customer ID

    b) Parent Customer ID

    c) Primary Contact ID

    d) Secondary Contact ID

    4) I utilized the NewID() function to assign IDs to each customer and contact, as required, in both work tables, for each record.

    5) I also had to perform additional preparation operations such as splitting the Contact name into First and Last names, since that is how CRM requires the data to be imported.

    These steps allowed me to have a base set of data that contained everything I needed in order to successfully import our Customer and Contact data.

    If I had chosen to allow CRM to create the ID, I would have had to update the Import Database to reflect that value.  Since there were so many relationships involved, I found it much easier to provide the ID myself.

    Sequencing

    Since everything in CRM is related to just about everything else, proper sequencing of import tasks is critical to the success of the operation.  When attempting to establish a relationship from one CRM record to another, that record being referenced must already exist within the system. If it doesn't, the operation will fail.

    For example: When setting the parentcustomerid for a Contact, you must have already imported the Customer in question before the relationship can be established.

    This caused me more than a little mental anguish as I worked through what I thought the "right" or "correct" method was.

    Note: I'm not sure there is a "right" or a "wrong" method.

     

    So here was the sequence at which I finally arrived:

    1) Import Customers who have Child Customers.

    2) Import Customers without Child Customers.

    The parentaccountid attribute was supplied from the database to establish the Parent/Child relationship with the Parent Customer.

    3) Import Primary Contacts associated with Customers from operation #2.

    The parentcustomerid attribute was supplied from the import database to establish the Parent/Child relationship with the Parent Customer.

    4) Import Secondary Contacts associated with Customers from operation #2.

    The parentcustomerid attribute was supplied from the import database to establish the Parent/Child relationship with the Parent Customer.

    5) Import Primary Contacts associated with Customers from operation #1.

    The parentcustomerid attribute was supplied from the import database to establish the Parent/Child relationship with the Parent Customer.

    6) For those Customers who had valid Primary Contacts, an update operation was performed against all Customer records that would create a link from the Customer to its Primary Contact by updating the value of the primarycontactid attribute to Primary Contact  ID found in the import database.

    Integration with the Business Operations System

    One of the more interesting things we did was to create two SQL Views that would simulate the table and column names that the BOS utilized so that no re-programming was required on the BOS side.  These views query the CRM SQL Filtered Views in order to return the requested data. We just modified the location of the linked tables within Microsoft Access and where pretty much done.

    The BOS application developer also added a CRM button to the main form that will take the Customer's ID and display the CRM record using the URL Addressable Forms technique outlined in the CRM SDK.  This allowed the BOS user to immediate jump to the Customer's CRM record should they need to review additional Customer detail.

    In the end, the user now has full access to the features and functionality provided by a true Customer Relationship Management application while still being able to utilize a highly specialized application to run their business operations.  The two are linked together so that a minimum of user retraining will be required ( over and above the normal CRM introduction classes ).

    Conclusion

    What this process allowed me to accomplish was getting all of the data into CRM without worrying about everything absolutely matching up during the first pass – which is how I started off the process and where I wasted much of my time.  It also provided a method to verify each step of the operation so that, in some cases, if the import was unsuccessful, I had a checkpoint that I could revert back to without having to delete everything and start over again.

    I also fixed a few issues with my Bulk Delete utility that allowed me to delete the CRM records without resorting to using the CRM UI ( and deleting 250 at a time ).

    Hopefully, I've provided enough insight into the process to get you to thinking about how you might conduct a similar operation of your own.  If not, just ask for clarification.

    Have a great weekend.

    Development, Dynamics CRM, Installation
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    3,684 views
  • Changing the default date/time display format

    Posted on March 29th, 2007 mitch Print Print No comments

    My current CRM installation involves the migration of customer data from the business system that runs the company to CRM.  While I am working through issues related to the migration process, I discovered that it would be very handy if I could see both the date and time for the created on Attribute displayed in the Active Accounts view.  Here's how I did it:

    1) Select Settings, Customization, Customize Entities.

    2) Customize the Accounts Entity.

    3) Click on Attributes

    4) Edit the createdon attribute.  You should see something like this:

    5) Change the Format to Date and Time, as shown below:

    6) Add the createdon attribute to the Active Accounts view, if it doesn't already exist.

    7) Save and Publish your changes.

    8) The Created On Attribute should now be formatted with both the Date and Time.

     

    Caveats

    The only issue I ran into was the fact that the Advanced Find still only recognizes the Date format of the createdon attribute.  If anyone knows a way around that, let me know and I'll update this article accordingly.

    Customization, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    1,897 views
  • CRM 3.0 SDK 3.0.6 Released

    Posted on March 29th, 2007 mitch Print Print No comments

    The following table describes the release history for the Microsoft CRM SDK

    Version 3.0.6, March 2007

    New and updated topics Description of changes
      Fixed broken links throughout document.
    Callout Source Code Sample Updated sample code.
    campaignactivity

    campaignresponse

    campaignitem

    Added related entity information for the field regardingobjectid.

    Fixed type information for the campaignitem.entitytype attribute.

    Client Side Scripting Bug fixes.
    Create a Customer Relationship Added sample code showing how to create a customer relationship.
    Create an Opportunity and Set a Picklist Added sample code showing how to instantiate types when creating an entity instance.
    CrmDateTime.Value Field

    ExecuteFetch Message

    Merge Message

    PublishXml Message

    UploadFromBase64DataActivity-
    MimeAttachment Message

    UploadFromBase64DataAnnotation Message

    Bug fixes in sample code.
    How to Retrieve Status Codes Added Visual Basic .NET version of this sample.
    Perform Bulk Delete Added sample code showing how to perform a bulk delete operation.
    Performance Best Practices Added topic describing best practices to help you write better performing code.
    Pricing Methods Added Pricing Methods topic.
    Related Documentation Added links to Microsoft CRM related content such as blogs, and so on.
    Report Development Environment Updated information on tools required for report development.
    Sample Code Reorganized sample code topics for ease of use.
    SetBusinessSystemUserRequest Class Corrected inconsistency in documentation. A value must be provided for the SetBusinessSystemUserRequest.ReassignPrincipal Field. Added sample code to the SetBusinessSystemUser Message.
    SystemUser In order to create an instance of a system user entity, the user must already exist in Active Directory.
    TargetOwnedIncident Class Bug fix. The documentation incorrectly stated that an incident can be assigned to another user using the Assign message. The incident entity does not support the Assign message.
    Using the Paging Cookie

    BusinessEntityCollection.PagingCookie

    PagingInfo.PagingCookie

    Added a description of how to use the PagingCookie in queries.

    Customization, Development, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    1,759 views
  • What "Next Door" means in Texas

    Posted on March 29th, 2007 mitch Print Print No comments

    A business associate told me this afternoon that he'll be in Houston on the 18th.  I told him I had no trouble running down to meet him.

    When he questioned the distance, I honestly replied:

    Anything less than 400 miles is considered next door in Texas.

     

    ( Houston is 250 miles or so from Dallas ).

    Meanderings
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    899 views
  • Importing Records and the CRMDeletionService

    Posted on March 27th, 2007 mitch Print Print No comments

    As you may know, each record within the CRM system has a unique identifier that identifies it within the system. This identifier is know as a GUID, or a Globally Unique ID.

    When you programmatically import records into CRM, you can either supply the GUID yourself, as a item within the import dataset, or you may allow CRM to generate the GUID.

    I was using a modified version of the Bulk Import Utility that I mentioned a while back and for this particular implementation, it made the import much more efficient if I supplied the GUID during the import process. 

    NOTE: In such a case all you do is assign the value of the GUID to the Entity's ID column, such as:

    Lookup keyTestValue = new Lookup();
    keyTestValue.Value = new Guid(myGUID);
    keyTestValue.type = EntityName.contact.ToString();

    This worked great for a while. I would test a section of the import process, delete the imported records, and reimport them later.

    Then I started running to very strange errors:

    Server was unable to process request.

    Not exactly though provoking or even any help at all in leading me to the root cause of the problem.

    The Problem

    It turns out, that even though I had deleted my test import records from CRM, they were still in the database.

    This is a common practice, and in case you didn't know, the CRM Client does not physically delete CRM records – it merely marks them for Deletion.  The CRMDeletionService is the process that runs periodically and makes everything in the CRM world right again.

    Except my CRM world wasn't right at all.  I couldn't continue my development efforts since I couldn't reliably test my import process, I had no idea why it was suddenly broken, and I had people at the customer site waiting on me to finish.

    I finally traced the issue to the fact that I was importing the GUID IDs along with the other Entity data.  I am making an educated guess that CRM was getting upset that it was finding those IDs existing within the database during the Create process and the import for that record was failing.

    I didn't want to result to manually deleting records from the CRM Base tables because that's against the rules, and I had no idea what magic was required to manually fire off the CRMDeletionService to have it do it's job.

    So I did what I usually do in cases like this: I sent a panicked email to a couple of my fellow CRM MVPs for thoughts and ideas.

    The Solution

    Michael Höhne came to my rescue with a bit of CRM knowledge that I am sharing now.  It turns out that you can instruct the CRMDeletionService to run manually, using the following instructions:

    1) Open a command prompt.

    2) Change your directory to: [CRM installation directory]\server\bin

    3) Run crmdeletionservice –runonce

    That will run the CRMDeletionService which will remove the deleted records from the database.

    CRM Deleted Records Backgrounder

    As mentioned above, the CRM client is not actually the process that deletes CRM records, it is the CRMDeletionService that does the actual work.  This is probably due to the fact that Delete operations are fairly intensive processes and due to the Entity Relationships you find within CRM, it can be extremely complex and time consuming.

    Rather than burden the user with this effort, the CRM Client merely updates the individual records and changes the DeletionStateCode to a value of 2.  The CRMDeletionService wakes up on a periodic basis ( unknown and not documented, BTW ), and deletes any record with the DeletionStateCode of 2.

    This makes for a fairly efficient system and an overall better user experience.

    Should you be accessing CRM data via the SQL Filtered Views, the DeletionStateCode value is taken into account and records marked for deletion are not returned.

    Likewise, the CRM Clients both mirror this functionality and totally ignore records marked for deletion.

    Future Development Efforts

    One of the first CRM add-ons I ever wrote was a utility that performed a bulk delete of CRM data, using the CRM WebService APIs.  Unfortunately, it doesn't always function as expected and I haven't had the time to invest into tracking down the issues relating to the failure of the CrmService.Delete call.  I think most of these issues are related to relationships and cascading issues.

    I will also be adding an option to physically delete the records marked for deletion by running the CRMDeletionService -runonce.  That will be a valuable edition.

    It may also be possible to create an Undelete utility for CRM but I have no idea if you can "legally" set the DeletionStateCode back to 0 through the CRM Web Services.  There will also be tons of issues related to relationships and cascading behaviors that need to be taken into account.  All of which means it may not possible, or practical to create such a utility.

    Development, Dynamics CRM, Installation
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    2,537 views
  • 10 years ago this week…

    Posted on March 27th, 2007 mitch Print Print No comments

    My friend Bruce Wittenberg called me yesterday to remind me that he knew where I was 10 years ago.  San Diego, to be specific, as a partner in a small technology integration firm.

    March 26, 1997 was also the date the Heaven's Gate cult decided to hitch a ride on the mothership hiding in the tail of the Hale-Bopp comet, as it passed Earth.  This was accomplished by committing suicide – all 39 of them.  I sure hope it was worth it…

    Since my parents still really don't know what it is that I do, besides "computer stuff," my Mom had my Dad call me to make sure I was still alive and not mixed up in any of that stuff.  Actually, I think several of my friends worried the same thing. :)

    I was working so much at the time, that I hadn't even heard the news till my Dad told me.

    Besides, that hole shaved-head celibate thing really wouldn't appeal to me…

    Meanderings
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    876 views
  • Verifying Form Context Before Invoking JavaScript Code

    Posted on March 19th, 2007 mitch Print Print 1 comment

    I was testing a callout-based solution for customer this afternoon when I ran into something very interesting when adding a new Contact ( to the Primary Contact Attribute of the Account ), using the Quick Create feature.

    Quick Create Backgrounder

    If you've never noticed, several CRM Lookup dialogs have a New button that allow you to create new records on the fly without having to change your context to that particular record type and selecting the New button.  CRM will display a dialog that contains all of the Business Required and Business Recommended Attributes for you to complete, as shown below:

     

     

    The Problem I Found

    It turns out that since this is my main development server, I have all types of strange configurations loaded, including something that uses the OriginatingLeadID attribute in the Form OnLoad event.  Unfortunately, since the OriginatingLeadID is not a Required or Recommended Attribute, it was not displayed on the Quick Create Form and therefore unavailable to the OnLoad event.  This produced the following Error:

     

    Ensuring a Smooth User Experience

    The easiest method for ensuring your OnLoad JavaScript functions as expected, is to verify the CRM Form Type using code similar to the following:

     

    // Perform this work only on Create
    if (crmForm.FormType == 1)
    {
      // do the work here
    }
    

     

    CRM Defines the following form types:

    Undefined Form Type = 0

    Create Form = 1

    Update Form = 2

    Read Only Form = 3

    Disabled Form = 4

    Quick Create Form = 5

    Bulk Edit Form = 6

     

    For more information on FormTypes and other CRM Form Properties, visit this link.

    Customization, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    2,578 views
  • Spring has sprung

    Posted on March 19th, 2007 mitch Print Print No comments

    So I was at the MVP Summit in Seattle last week.  Naturally, I washed my truck the day before I leave town and again, naturally, I park it outside under an Oak tree.

    I have five Oak trees at my house and since it is Spring and Momma Trees and Daddy Trees are doing what Momma and Daddy trees do to make baby trees.

    This means my newly washed truck is both sticky and is covered with a fine layer of green coloring.

    At least my truck was all decked out for St. Patty's Day.  Ugly, but in the spirit of the Irish, nonetheless.

    Meanderings
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    946 views
  • MVP Summit Wrap-up

    Posted on March 15th, 2007 mitch Print Print No comments

    I've been in Seattle all week attending the 2007 MVP Summit and besides catching a cold, I've had a great time.  I met some fellow MVPs, and got to attend some interesting technical talks with the Microsoft folks.

    I want to thank Microsoft for the invitation and for rolling the welcome mat for the MVPs.

    Misc
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    1,112 views