Neil Huffman's profileProductiveGap Microsoft ...BlogLists Tools Help
No list items have been added yet.

Feed

The owner hasn't specified a feed for this module yet.

ProductiveGap Microsoft Dynamics CRM Developer's Blog

Your Success is our Passion! - www.productivegap.com - Austin, Texas

11 things to know about customization

The used to be 6 things to know about customization in Microsoft CRM.  Now, there are 11. 

Taken from the Microsoft.com Using CRM site:

1. Metadata-driven customizations Considerations for customizing Microsoft Dynamics CRM.

2. Security and customization Describes the privileges you must have to access Customization features and how security applies to the customizations that you create.

3. Form and view customizations The most common types of customizations. What you can do and the process to apply changes.

4. Personal customizations Let users personalize Microsoft Dynamics CRM to meet their work styles.

5. Entity customizations Explains what an entity is and how you can customize and relate entities.

6. Transportable customizations How to move your customizations between Microsoft Dynamics CRM servers.

7. Report customizations Entity customizations usually need to be reflected in customized reports. What reporting options are available to you and the skills you need to customize them.

8. Workflow customizations Create automated processes without programming.

9. Application integration features Include other Web applications within Microsoft Dynamics CRM or customize navigation.

10. Form scripting customizations Apply business process customizations on the client.

11. Supported customizations 

-Neil Huffman

The JavaScript snippets directory

Stunnware has put together a great list of JavaScript snippets for Microsoft CRM.  If you need JavaScript for Microsoft CRM, then he is the guy.

Source: The JavaScript snippets directory

-Neil Huffman

Integrating Windows Explorer Files and Folders into CRM Tabs

Here is a screenshot of an integration with Windows Explorer.  It requires a Sharepoint Web Part, customizing the Account Form with an IFrame to call the Sharepoint webpage, and some Jscript to pass the Account name in order to display the correct folder on the system.  Check out Matt Whitteman's post on the CRM Team Blog for the complete solution.

Integrating Windows Explorer

AccountForm2.jpg

Source: Integrating Windows Explorer Files and Folders into CRM Tabs

- Neil Huffman

XML Projects & FetchXML into a DataSet

I am doing alot of work with XML for a current project.  The three pieces I am working on are:

  1. Export CRM Data to XML File
    • FetchXML makes this very easy giving you the InnerXML to pass into your XMLDocument
    • There are some great tools to help you generate the FetchXML strings you need (FetchXML Builder & FetchXML Wizard)
  2. Import Data from XML File into CRM
    • I am just starting on this project.  I plan to use the new Bulk Import Whitepaper and sample code that comes with it.  Currently the tool takes a CVS file and passes it into a DataSet.  I plan to add functionality to parse a XML File into the DataSet and go from there.

I will be working on these the next couple of weeks and post my sample solutions.

Here is part of a post from Ronald Lemmen that deals with this subject:

Now with this knowledge you will understand why I post this piece of code:

private DataSet FetchDataSet(string fetchXml) {
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
//service.UnsafeAuthenticatedConnectionSharing = true; //enable in secure migration programs
string strResult = service.Fetch(fetchXml);
DataSet ds = new DataSet();
System.IO.StringReader reader = new System.IO.StringReader(strResult);
ds.ReadXml(reader);
return ds;
}

I'm just typing this way to often and I prefer to use copy and paste.
Furthermore a link to a previous post on how to quickly create a fetchXML:
http://ronaldlemmen.blogspot.com/2006/11/using-advanced-find-for-fetchxml.html
And a link to another post on how to make sure that you do fetch all records and not only the first 5000:
http://ronaldlemmen.blogspot.com/2006/08/fetch-all-records.html

Source: FetchXML into a DataSet

First 6 things to know about customization

Taken from the Microsoft.com Using CRM site:

You have to customize, or supervise customization of, Microsoft Dynamics CRM 3.0 and you do not have time to attend training or read a long book. You have opened Microsoft Dynamics CRM and are familiar with the basic features for Sales, Service, and Marketing. You want to make sure that you have a good, high-level understanding of the customization capabilities and are using the correct customization feature for the business requirements. You also want to be aware of common issues other users have experienced. With that goal in mind, these are the first six things to know about how to customize Microsoft Dynamics CRM.

This series of articles describes some basic customization features and concepts. These articles highlight key information about the capabilities and limitations of these feature areas.

1. Meta-data driven customizations - Considerations for customizing Microsoft Dynamics CRM.

2. Security and customization - Describes the privileges you must have to access Customization features and how security applies to the customizations that you create.

3. Form and view customization - The most common types of customizations. What you can do and the process to apply changes.

4. Personal customizations - Let users personalize Microsoft Dynamics CRM to meet their work styles.

5. Entity customization - Explains what an entity is and how you can customize and relate entities.

6. Transportable customizations - How to move your customizations between Microsoft Dynamics CRM servers.

Read more...

Source: First 6 things to know about customization

Discussion Regarding CRM Data Import Strategies

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.

Tags: Development, Dynamics CRM, InstallationDevelopment, Dynamics CRM, Installation

Source: Discussion Regarding CRM Data Import Strategies

Old House in Seattle

This is my old house in Bothell, Washington when I worked for Microsoft.


Old House

Save time when you import leads, contacts, and accounts

When you have data that you’d like to import into Microsoft Dynamics CRM, it can be challenging to figure out where to start, and to understand why some data doesn’t go in as smoothly as you might expect. The basic concept is simple: somewhere in the import process you have to match each column in your data with its destination in Microsoft Dynamics CRM. The Bulk Import Wizard offers one way to do this matching: it lists each of your source columns, and for each one, you select the appropriate attribute...(read more)

CRM Security Model Internals

In this post I’ll describe some of the CRM Security Model internals. I’ll describe how roles and privileges are used under the covers, how security is enforced for different operations, and some of the internal structures that make it possible.

Overview

Just in case we need a quick refresher on the basics...

The CRM security model uses Windows-based authentication (Kerberos/NTLM), and internally-driven authorization. It’s basically a role-based security model, where a role is conceptually some class of person (Marketing Professional, System Administrator, etc.). CRM supports object-level (i.e. row-level) security, with support for sharing and assignment. Depending on your role and sharing information, you can have access to an object even if you’re not the owner.

Implementation

In v1.0 and v1.2, CRM used windows security descriptors and the windows AccessCheck function (actually AuthzAccessCheck) to actually validate a user’s access. A security descriptor is the same thing controls your rights on files, directories, etc. A CRM security descriptor would contain information about what users, teams, and roles had what specific rights on an object, and it would be stored in the row of the object. Users, teams, and roles would all be represented by some AD object (user object or an AD group). To check access, we would retrieve the security descriptor and call the AccessCheck function using the token of the user who was logged into CRM, which would contain the groups of all the roles and teams of which they were a member.

In v3.0, we moved to a database-driven security model since it gave us many benefits over the security descriptor model.

Roles and Privileges

A privilege is conceptually a right on an action. For example, example, holding the “Read Account” privilege gives you the right to try to read an account. Without the privilege, we don’t even bother to show the Account entity in the UI. We call this the PrivilegeCheck. What actually controls your access to a particular object instance (or row), is the depth of privilege and the relative depth of the business unit to which you belong to the business unit to which the object belongs (unless it’s an Organization-Owned object). We call this part the AccessCheck. Here’s an example:

If Bob has the “Read Account” privilege at the Parent:Child depth, he can read account A, but not Accounts B or C. If he didn’t have the privilege at all, Accounts wouldn’t even show up in the UI.

Depth is the pie-pieces you see in the Role Editor UI. So a role is really a collection of {Privilege, Depth} pairs, and a full security check = PrivilegeCheck + AccessCheck (AccessCheck implicitly checks privileges, too, but a PrivilegeCheck is more efficient since we don’t need any object information to deny someone who doesn’t even have the basic privilege).

Sharing and Assignment

CRM also supports sharing and assignment. Assignment is obviously just changing the owner of an object. Sharing provides the ability to override AccessCheck-restrictions, but PrivilegeCheck-restrictions still apply. So in the example above, if Account B was shared with Bob with Read rights, he could read B, but still not C. If Bob didn’t hold the read privilege at all, he still couldn’t read A, B, or C, even with the sharing.

PrivilegeCheck and AccessCheck

Okay, what actually happens with security when you view a grid, update an Account, etc.? Let’s start by going through the flow of updating an Account. I’ll look at it from an SDK perspective, since the UI actually does some additional stuff. Here’s the flow:

After the privilege check, we continue on with other business logic like basic validation of input against business rules or other entity-/operation-specific stuff. For the access check, we need to retrieve some security information from the row of the Account. In particular, we need to know the Primary Key, OwnerId, and OwningBusinessUnit. Once we have that, we can do the access check:

Let’s go through the steps here:

1. If the user is the owner of the record, the depth stuff doesn’t matter (remember, we’ve already gotten past the PrivilegeCheck part), so they have access.

2. Next, we need to determine the minimum privilege depth required:

     a. If the user is in the same business unit as the object, the user needs “Business” depth (half a pie from the UI).

     b. If the object is in one of the child business units of the user’s, the user needs “Parent:Child” depth (3/4 pie from the UI).

     c. Otherwise, the user will need “Organization” depth to read the object (for example, if it’s in a parent or sibling business unit).

We can do all these checks from cache lookups: the user’s business and the organization’s business hierarchy are cached, as well.

3. Then we find out if the user has all the required privileges at the minimum required depth. Included in the privilege information we cache for the user is the maximum depth at which they hold the privilege.

4. If the user doesn’t get access through the owner checks or role-based checks, we check sharing next. CRM stores all sharing information in a table called PrincipalObjectAccess which maps users and teams to objects that have been shared to them explicitly or via cascaded operations.

5. If the user still doesn’t have access by this point, we return an Access-Denied error.

So basically that’s the security part of what happens when you use the Update API or when you click “Save” on a form (though we wouldn’t even render the “Save” button if you didn’t hold the privilege).

What about when you view a grid? Well, we don’t want to retrieve a bunch of records and then do an access check row-by-row in the middle-tier. We want to be able to do the security checks in SQL so we can get good paging performance and not retrieve more records than are necessary to satisfy the user’s request.

So we invert the process slightly. Instead of determining a minimum “Read” privilege depth by looking at the relative positions of the user and the object in the business-hierarchy, we get the maximum “Read” privilege depth on the entities being queried and use that to limit the query to those business units the user will be able to read. We also do the ownership check and sharing checks as part of the query as well (we still do a PrivilegeCheck for “Read” on the entities being queried first, of course):

SELECT top 51 AccountId

FROM Account

WHERE

-- user is the current user

(Account.OwningUser = <current_user>)

OR

-- user gets access via role access (this example is checking Parent:Child)

(Account.OwningBusinessUnit in

(SELECT SubBusinessId

FROM BusinessUnitMap

WHERE BusinessUnitId = <current_user_business_unit>))

OR

-- user gets access via sharing

(AccountId in (SELECT ObjectId

FROM PrincipalObjectAccess poa

JOIN SystemUserPrincipals sup on poa.PrincipalId = sup.PrincipalId

WHERE sup.SystemUserId = <current_user> AND

poa.ObjectTypeCode = <entity_object_type> AND

((poa.AccessRightsMask | poa.InheritedAccessRightsMask)&1) = 1)))

This is a simplified query for a user who has the “Read” account privilege at “Parent:Child” depth. The user can get access through ownership, role access, or sharing. The ownership check is pretty straightforward. For the role check, we need to look at objects in the user’s business or child businesses because they have “Parent:Child” access. We use a utility table, BusinessUnitMap, that denormalizes the business hierarchy into a flat list for each business unit.

For the sharing check, we need to retrieve the entity rows where the PrincipalObjectAccess table has entries for the entity with read access (the “& 1” part) where the Principal is the user or any teams of which the user is a member. We use the utility SystemUserPrincipals table to get a flat list of all the principals of which the user is a member (including a self-mapping to the user). The “top 51” just means we are retrieving the first page of a grid with 50 records per page. The extra record is used to let the caller know whether there are more records or not.

Wrapping Up

I hope you found this brief look under the covers interesting. If you have any questions, comments, requests on the CRM Security Model, we’d love to hear from you -- please add a comment to the post and I’ll be happy to respond.

Jay Grewal

Source: CRM Security Model Internals

HOT! Ben Riga talks about the Convergence Live crm demo

From Ben's Blog : One of the coolest things I saw at Convergence this year was a demo of Dynamics Live CRM. We've been talking about this since last summer but this was the first time we demonstrated it publicly. Brad Wilson the GM for the group showed how Live CRM will look out on the cloud running in Microsoft data centers. More importantly for developers and ISVs he showed how simple it'll be to deploy customizations to a Live CRM installation. Brad Wilson (GM, CRM) and Bill Paterson (Group Product...(read more)

Source: HOT! Ben Riga talks about the Convergence Live crm demo