Knowledge found and lost while working with Microsoft Dynamics CRM
RSS icon Home icon
  • Bulk Attribute Deletion Utility Updated

    Posted on July 28th, 2010 Mitch Milam Print Print 1 comment

    I’ve modified the Bulk Attribute Deletion Utility to support Internet Facing Deployment ( IFD ) for CRM 4.0.

    Download it here.

    Thanks to my friend George Doubinski I was able to connect to a CRM installation via IFD for testing.

    Please let me know if you run into any issues.

    Customization, Development, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    236 views
  • Exception handling when working with the CRM Web Services

    Posted on July 26th, 2010 Mitch Milam Print Print 2 comments

    I just ran into something that I have never seen before related to a SoapException:

    I was updating my Export JavaScript utility when I received an error message that was blank.  Very odd, I thought.  After a bit of digging, I found the error:

    Server was unable to process request.
    —> Exception has been thrown by the target of an invocation.
    —> The type initializer for 'Microsoft.Crm.WebServices.CrmAuthenticationSoapExtensionBase' threw an exception.
    —> The server is not operational.

    Now at this point, I really don’t know what happened, but my development CRM 4.0 server was in some type of non-functional state that required me to perform an IISRESET to recover from.  That is not the interesting thing here today.

    The interesting thing is where the error message was found.  Here is an example the code that normally use to detect an error when using the CRM Web Service:

    catch (SoapException ex)
    {
        MessageBox.Show(ex.Detail.InnerText,
                        Properties.Resources.MSG_AN_ERROR_HAS_OCCURRED,
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
    }

    Usually, the actual error message is found in the SoapException.Detail property and you can access it via the InnerText or InnerXml properties, depending on how you wish to handle it.

    Today, the error message was actually in the SoapException.Message property, which I find very odd.  As I said, I’ve never seen this before so I don’t know what happened, but in order to prevent a blank error message from appearing to the user, I created the following work around:

    catch (SoapException ex)
    {
        string errorMessage = ex.Detail.InnerText;
    
        if (string.IsNullOrEmpty(errorMessage))
        {
            errorMessage = ex.Message;
        }
    
        MessageBox.Show(errorMessage,
                        Properties.Resources.MSG_AN_ERROR_HAS_OCCURRED,
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
    }

    As you can see, I just take into account the possibility that the Detail.InnerText property is blank and if so, just use the standard Message property to be safe.

    Customization, Development, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    274 views
  • Marketing List Manager Screencast Uploaded

    Posted on July 20th, 2010 Mitch Milam Print Print No comments

    I took a break from recording some training videos tonight to record a quick screencast of the Marketing List Manager solution I created for CRM 4.0.

    I walk you through creating workflows that use the Marketing List Manager to add and remove a Contact from a marketing list.

    You may view it here, under the Additional Downloads section.

    Customization, Dynamics CRM, Workflow
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    231 views
  • Creating a query to find all users with a specified security role

    Posted on July 20th, 2010 Mitch Milam Print Print No comments

    I ran into an interesting requirement this morning that let’s me show off one of my favorite CRM add-on utilities: Stunnware Tools.  Let’s cover both.

    The Requirement

    I needed to create a list of users that were members of a specific security role.  Rather than writing an application or designing a SQL query, I opened Stunnware Tools for Microsoft Dynamics CRM so that I could create a query in the FetchXML Wizard.

    Using the FetchXML Wizard

    The FetchXML Wizard allows you to query CRM by building a FetchXML query.  Here is a screen shot of the Designer:

    image

     

    Designing the Query

    The following steps were required to created the desired query:

    Step 1:

    Query the SystemUser entity and return the Full Name of the user.

    Step 2:

    Include a Linked Entity that links the SystemUser Entity to the SystemUserRoles Entity

    Step 3:

    Add another Linked Entity from SystemUserRoles to Role.  This link will have a filter applied where the Name of the Role is equal to salesperson.

    Here is the resulting FetchXML query:

    <fetch mapping="logical" count="50" version="1.0">
      <entity name="systemuser">
        <attribute name="fullname" />
        <link-entity name="systemuserroles" from="systemuserid" to="systemuserid">
          <link-entity name="role" from="roleid" to="roleid">
            <filter>
              <condition attribute="name" operator="eq" value="salesperson" />
            </filter>
          </link-entity>
        </link-entity>
      </entity>
    </fetch>
    

    Which produces the following result set:

    image

     

    This whole process took me less than 5 minutes because the FetchXML Wizard Query Designer understands the links between CRM Entities and allowed me to quickly select those links and specify the necessary filter to produce the dataset I needed.

    The Export to Excel module included in Stunnware Tools allows me to export the above result set to an Excel worksheet.

    More About Stunnware Tools

    There are two editions:

    • The Community Edition: It's free and contains the Metadata Viewer, FetchXml Wizard and Excel Export.
    • The Professional Edition: A subscription-based version with access to all tools of the Community Edition plus the Code Generator for C# and VB.NET, the CRM Help File Generator, additional features of the FetchXml wizard and the Customization Comparer.

    Stunnware Tools is probably the most valuable Dynamics CRM add-on that I have.  I use it on a weekly, if not daily basis and which makes me a much more productive developer.

    Administration, Customization, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    418 views
  • Free Utility Released: Bulk Delete CRM Attributes

    Posted on July 19th, 2010 Mitch Milam Print Print 10 comments

    I’ve released a new free utility for CRM users that allows you to bulk-delete CRM Entity Attributes.

    The user interface is fairly straightforward, as you can see below:

    image

    How It Works

    The operation is pretty simple:

    1) Select if your organization is OnPremise or CRM Online.

    2) Enter the name of your server and the credentials required to connect properly.

    3) Select the organization you wish to connect to.

    4) Select the Entity you wish to delete attributes from.

    5) Select the attributes to delete.

    6) Click the delete button.

     

    Behind the Scenes

    This utility uses standard CRM SDK methods to delete the attributes you specify.  A log file is written to the location where the application is stored.  All actions will be logged and if errors are encountered, the log file will be displayed at the end of the processing cycle so you can see what happened.

    Remember: The same rules that would apply if you were to delete an attribute through the CRM user interface apply here.  For example: if the attribute is used on a form, a view, or within a workflow, the deletion will fail and you will be given a list of locations where the attribute is in use.  You must remove the attribute from those locations before you can continue.

     

    Download

    You may download it here.

    Administration, Customization, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    746 views
  • CRM JavaScript Export Tool Updated

    Posted on July 12th, 2010 Mitch Milam Print Print 1 comment

    I have updated the CRM JavaScript Export Tool to include the following major enhancements:

    1) Added support for CRM Online.

    2) Added support for the generation of a Visual Studio 2010 project.

    3) Changed the naming convention of the export folder so that it also contains the date and time of the export.

    Here is how the new user interface looks:

    image

    You can find it on the Free Utilities page.

    Customization, Development, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    389 views
  • Learning how to query for Marketing List Members

    Posted on July 5th, 2010 Mitch Milam Print Print No comments

    This morning I was adding some functionality to my Dynamics Tutorials site and needed to determine if a user was a member of a specific marketing list.

    No problem, I thought.  I opened up the most excellent Stunnware Tools to create the query.

    The only problem is that the Marketing List Member entity, listmember, does not support the RetreiveMultiple message, which means I can’t use QueryExpression to perform the query.

    After digging around a while, I found that I could use QueryExpression but I would have to use the LinkEntity property to properly assemble the query.  Here is what I came up with:

    bool retVar = false;
    
    QueryExpression query = new QueryExpression { EntityName = EntityName.list.ToString()};
    
    LinkEntity linkEntity1 = new LinkEntity { JoinOperator = JoinOperator.Natural,
                                              LinkFromEntityName = "list",
                                              LinkFromAttributeName = "listid",
                                              LinkToEntityName = "listmember",
                                              LinkToAttributeName = "listid",
                                              LinkCriteria = new FilterExpression() };
    
    linkEntity1.LinkCriteria.FilterOperator = LogicalOperator.And;
    
    linkEntity1.LinkCriteria.AddCondition(new ConditionExpression { AttributeName = "listid",
                                                                    Operator = ConditionOperator.Equal,
                                                                    Values = new Object[] { marketingListId } });
    
    linkEntity1.LinkCriteria.AddCondition(new ConditionExpression { AttributeName = "entityid",
                                                                    Operator = ConditionOperator.Equal,
                                                                    Values = new Object[] { userId } });
    
    query.LinkEntities.Add(linkEntity1);
    
    RetrieveMultipleRequest request = new RetrieveMultipleRequest { ReturnDynamicEntities = true, Query = query };
    RetrieveMultipleResponse response = (RetrieveMultipleResponse)crmService.Execute(request);
    
    retVar = (response.BusinessEntityCollection.BusinessEntities.Count > 0);

    How It Works

    1)  We start by querying the Marketing List Entity ( list ).

    2) We create a link entity that joins the Marketing List Member Entity to the Marketing List Entity.

    3) The search criteria is actually specified on the linked, Marketing List Member Entity.  We’re asking for a specific userId and a specific marketingListId.

    4) Next we add the linked entity to the query.

    5) Finally we prepare and execute the request.

     

    Since I am only interested if the contact exists within the marketing list, I simple set a boolean variable to true or false depending if the number of records returned ( found in the BusinessEntityCollection ) is greater than zero.

     

    References

    Customization, Development, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    292 views
  • Decrypting CRM JavaScript Runtime Errors

    Posted on June 28th, 2010 Mitch Milam Print Print 2 comments

    If you have spent any time at all writing JavaScript for CRM you have probably made at least one programming error that has resulted in your page failing to work properly.

    CRM will display the following in the bottom-left corner of your page:

    image

    Not very helpful, and sometimes not very noticeable either. However, when you close the window CRM will display the following dialog:

    image

    Now we’re getting somewhere.  This is CRM’s built-in error collection tool that the CRM development team uses to record and track errors within CRM.  The data is scrubbed of anything that resembles personal or proprietary information then sends the data ( as long as you click Send Error Report ) to a collection server at one of Microsoft’s Internet sites.

    But, this information can also be helpful to you, since you caused the error.

    If you click the middle link, View the data that will be sent to Microsoft you will see the actual JavaScript error that cause the error on the page:

     image

    Well that is all great, good, and wonderful, but what does it mean?  Expected what???

    You have two options:

    1) You can hunt down an Internet that has a character table that lists characters and their numeric value; or:

    2) You can turn to Google.  Simply paste the message into the search box of Internet Explorer ( the top box ), press Enter, and the results will be shown in your default language on the Google search page:

    image

    Alas, Bing Search does not seem to offer the same capability.

     

    So there you have it.  Hopefully this will help the next time you accidentally introduce an error into your code.

    As a final note, sometimes the information shown in the error message dialog is of no use to you at all.  You will see something like, an error occurred on line 743, character 15.  Since CRM wraps your code within their code, this type of information is less than useful to you so you may spend more than a little time tracing down your exact problem.

    Special thanks to Daniel Cox who showed me the Google trick.

    Customization, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    692 views
  • Exploring the CRM Metabase and Those ‘Of’ Attributes

    Posted on June 21st, 2010 Mitch Milam Print Print 1 comment

    The CRM Metabase web service allows you to retrieve Entity and Attribute information. If you’ve ever retrieved Entity information you may have noticed some interesting things about the list of attributes returned.

    Some of the attributes you will see are not normally displayed in the list of attributes you see when viewing the Entity from within the CRM user interface.

    I call these attributes the ‘Of’ attributes because they have properties that end with ‘Of' and are related to, or based on, other attributes.

    If we explore the CRM AttributeMetadata class you will see the following three properties:

    AggregateOf
    Gets the name of the attribute that aggregates the value of this property.

    AttributeOf
    Gets the name of that attribute that this attribute extends.

    CalculationOf
    The SDK description says 'For internal use only, but attributes with this property typically contain currency data.

     

    Here are examples of ‘Of’ Attributes:

    From the Contact Entity:

    Attribute Name Attribute Of
    parentcustomeridname parentcustomerid
    donotbulkemailname donotbulkemail

     

    From the Account Entity:

    Attribute Name Calculation Of
    Aging60_Base Aging60
    Revenue_Base Revenue

     

    From the Contact Entity:

    Attribute Name Aggregate Of
    owningteam ownerid
    accountid parentcustomerid

     

    So why is this important to me?

    Well, that depends on what you are doing with the Metabase.  If you are producing documentation, these attributes may or may not me useful to you.

    If you are using the Metabase web services to delete attributes, then these attributes are of no use to you because they can’t be deleted since they are maintained internally by CRM.  If you delete the ‘parent’ attribute, the related attribute is also deleted.  If you attempt to delete the internally generated attribute, you’ll receive an error.

     

    Checking for ‘Of’ attributes

    Here is how you check for ‘Of’ attributes using code:

    AttributeMetadata attribute = entityResponse.EntityMetadata.Attributes[0];
    
    if (
    (attribute.AttributeOf == null) &&
    (attribute.AggregateOf == null) &&
    (attribute.CalculationOf == null)
    )
    {
        // do something interesting
    }

    Customization, Development, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    436 views
  • Sharing Records Programmatically

    Posted on June 15th, 2010 Mitch Milam Print Print 2 comments

    On occasion I’ve had the need to programmatically share a record with a CRM user or team.  I noticed this morning that the CRM user interface and the CRM web service call to Grant Access don’t actually have the same number of options.

    Here is how you would share a record manually, through the CRM interface:

    image 

    Here is how you do share a record via code ( from the CRM SDK ):

    // Create the SecurityPrincipal Object
    SecurityPrincipal principal = new SecurityPrincipal();
    principal.Type = SecurityPrincipalType.User;
    
    // PrincipalId is the Guid of the user to whom access is being granted
    principal.PrincipalId = new Guid("7B222F98-F48A-4AED-9D09-77A19CB6EE82");
    
    // Create the PrincipalAccess Object
    PrincipalAccess principalAccess = new PrincipalAccess();
    
    // Set the PrincipalAccess Object's Properties
    principalAccess.Principal = principal;
    
    // Gives the principal access to read
    principalAccess.AccessMask = AccessRights.ReadAccess;
    
    // Create the Target Object for the Request
    TargetOwnedAccount target = new TargetOwnedAccount();
    
    // EntityId is the Guid of the account access is being granted to
    target.EntityId = new Guid("6A92D3AE-A9C9-4E44-9FA6-F3D5643753C1");
    
    // Create the Request Object
    GrantAccessRequest grant = new GrantAccessRequest();
    
    // Set the Request Object's properties
    grant.PrincipalAccess = principalAccess;
    grant.Target = target;
    
    // Execute the Request
    GrantAccessResponse granted = (GrantAccessResponse)service.Execute(grant);

    AccessMask Property

    The AccessMask property defines how the record should be shared. The following values are available:

    AppendAccess

    Specifies the right to append the specified object to another object.

    AppendToAccess

    Specifies the right to append another object to the specified object.

    AssignAccess

    Specifies the right to assign the specified object to another security principal.

    CreateAccess

    Specifies the right to create an instance of the object type.

    DeleteAccess

    Specifies the right to delete the specified object.

    ReadAccess

    Specifies the right to read the specified type of object.

    ShareAccess

    Specifies the right to share the specified object.

    WriteAccess

    Specifies the right to update (write to) the specified object.

    For additional information, visit the CRM SDK topic: AccessRights Enumeration (CrmService).

    The example above gives Read access to a record.  To specify more than one access right, you use the C# OR assignment operator so that your code looks something like this:

    principalAccess.AccessMask |= AccessRights.ReadAccess;
    principalAccess.AccessMask |= AccessRights.WriteAccess;

    The Append Oddity

    I noticed something odd about the Assign right this morning.  If you are programmatically sharing the record you must supply both Append and AppendTo rights in order for CRM to fully give Append rights to the record. Here is the code:

    principalAccess.AccessMask |= AccessRights.AppendAccess;
    principalAccess.AccessMask |= AccessRights.AppendToAccess;

    If you only supply Append and view the sharing assignments through the CRM user interface, you will not see the Append box checked.

    Customization, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    434 views