Knowledge found and lost while working with Microsoft Dynamics CRM
RSS icon Home icon
  • Marketing List Manager Add-On Updated

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

    I’ve updated my Add To Marketing list add-on with additional functionality and a new Name.

    New Name

    The new name is Marketing List Manager for Dynamics CRM

     

    New Functionality

    Marketing List Manager is an plug-in that allows you to both add and remove members from a marketing list – a feature that is not currently available in Microsoft Dynamics CRM 4.0.

    Read more about it here.

    Dynamics CRM, Workflow
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    286 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
  • CRM Add-Ons Updated

    Posted on July 3rd, 2010 Mitch Milam Print Print No comments

    Last year I created an add-on for Dynamics CRM 4.0 that I called Data Validation.  It had two functions:

    1. User interface validation
    2. Email management.

    This week I decided to split those functions into two separate products.

    I also change the licensing from a per-organization fee to a simple flat-fee.

    You may read more about these products by visiting their respective product pages:

    Email Manager

    Data Validation

    Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    221 views
  • Issue found while upgrading reports from SQL 2005 to SQL 2008

    Posted on July 1st, 2010 Mitch Milam Print Print No comments

    One of my local customers recently moved from Small Business Server 2003 to Small Business Server 2008.  Among other things, this required a move from SQL Server 2005 to SQL Server 2008 as well.

    The movement of the databases went pretty much without issue, but we ran into some strange behavior with some of the custom CRM reports they had created.  The error looked something like this:

    image

    Not very helpful at all.

    After reviewing the report in Visual Studio and still not finding any issues, I finally started looking at the system itself.  That’s when I found this in the SQL Server’s Event Log:

    Report data set execution failure. Error: Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.
    Incorrect syntax near ','.

    Hmm. It keeps getting better and better. Now what exactly does that mean? 

     

    Background

    It turns out that when the SQL commands they had written to populate the report were sent to the SQL server, they were combined with other SQL commands.

    Unfortunately, SQL didn’t like the way the commands were combined.  It wanted you to use a semi-colon ( ; ) to separate the commands so it could determine how the commands should be run.

    Which is exactly what the error message states.

     

    The Solution

    To fix the issue, all I did was to add a semi-colon ( ; ) to the beginning of the custom SQL statement, which looked something like this:

    ;WITH FilteredAccount AS

    And that solved the problem and the reports ran successfully.

    Dynamics CRM, Reporting
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    255 views
  • Teaching a CRM Bootcamp in August

    Posted on July 1st, 2010 Mitch Milam Print Print No comments

    Hi Folks,

    Just wanted to let you know I’ll be teaching part of a CRM bootcamp in Raleigh, North Carolina in August, if you have training budget and interest. 

    Information on the entire bootcamp may be found here.

    I’ll be teaching these classes:

     

    Monday, August 9th:

    80003A:  Workflow in Microsoft Dynamics™  CRM 4.0

     

    Tuesday, August 10th through Thursday, August 12th:

    8969: Extending Microsoft Dynamics CRM 4.0

    Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    193 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
  • White Paper: Microsoft Dynamics CRM Online: Security Features

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

    Microsoft released a new white paper today.

    Overview:

    Microsoft takes a holistic approach to providing a highly secure environment for Microsoft Dynamics CRM Online. After an overview of the inherent risks to three key areas of the service, the remaining sections of this paper describe how Trustworthy Computing, Microsoft’s core commitment to build software and services that better help protect customers and the industry, is reflected in the design and operation of Microsoft Dynamics CRM Online.

    CRM Online, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    382 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
  • Non-Interactive Users and CRM Online

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

    About a year ago Jon White’s article concerning a CRM Online Non-Interactive user type was posted on the CRM Team blog. I thought I’d add some additional information I found last week.

    But first, a bit of background from Jon’s article:

    A non-interactive user is a user account in Microsoft Dynamics CRM Online that can access the system but only via the web service layer. Essentially, that user can not use the user interface. Service accounts are used to access CRM Online using the service to service model. A service account is a non-interactive user account with the proxy role assigned to it. Microsoft Dynamics Online allows 5 free non-interactive user accounts. To make the user account a non-interactive account, you need to change the access mode. The access attribute is not visible in the UI by default.  The attribute is “access mode”, you can either customize the form to show it, or manipulate it by an SDK call.  Setting the access mode to non-interactive simultaneously frees up a license and prevents that identity from logging in interactively.

    He goes on to tell you how to add the Access Mode field to the System User Entity form so that this field can be changed by the administrator.

    You may also find it useful to put the Access Mode on the Active Users View, so that it displays when you are reviewing your user list:

    image

     

    Interesting Observation

    Last week I was discussing non-interactive users with a colleague when I noticed a rather interesting situation:  If you are out of user licenses for CRM Online you can’t create a non-interactive user through the CRM user interface. Curious, but understandable.

    In a nutshell, the New User wizard will inform you that you are out of licenses and not allow you to continue.

    You can circumvent the issue by performing these steps:

    1. Temporarily disable a user
    2. Create a new user and change their Access Mode setting to Non-Interactive
    3. Re-enable the user disabled in step 1.

    That should do it.

     

    Programmatic User Creation

    Nothing, however, will stop you from creating a user programmatically.  You just need to supply the proper values.  Here’s some sample code:

    systemuser user = new systemuser();
    
    user.accessmode = new Picklist(SystemUserAccessMode.NonInteractive);
    user.firstname = "system";
    user.lastname = "integration";
    user.businessunitid = new Lookup("businessunit", new Guid("{C9694BD7-C0C4-DE11-B95D-02BF0A0679DB}"));
    
    service.Create(user);

    As you can see, you only need four properties:

    Access Mode

    In this case, we’re going to supply NonInteractive as the value, since that is the purpose of our discussion.

    First Name

    First name of the user.

    Last Name

    Last name of the user

    Business Unit ID

    This is the ID of the business unit the user belongs to.

     

    Calling the CrmService.Create method to actually create the user.

    Afterwards, any connection that you need to make to CRM Online can use the new non-interactive user instead of a fully-licensed person.

    Administration, CRM Online, Dynamics CRM
    1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
    Loading ... Loading ...
    487 views