<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Michaeljon Miller : Microsoft CRM</title><link>http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx</link><description>Tags: Microsoft CRM</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Why MS-CRM isn't a CRM product</title><link>http://blogs.msdn.com/mikemill/archive/2007/03/27/why-ms-crm-isn-t-a-crm-product.aspx</link><pubDate>Tue, 27 Mar 2007 21:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1966408</guid><dc:creator>mikemill</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/1966408.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=1966408</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=1966408</wfw:comment><description>&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;For the longest time I've held the belief that the underlying infrastructure behind MS-CRM was there to support arbitrary business applications. It's funny, for the last six months I've been betting my career on that belief, and even more today, I truly believe that the core value proposition is that CRM is so extensible that its CRM-ness becomes secondary to how and why people buy it.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;I've been talking to a number of customers and partners who have purchased CRM not for the CRM aspects at all (although I suspect they end up using quite of bit of the functionality) but for the platform components. It seems to have come full circle - the CRM product was, a very long time ago (in industry terms) designed to be the platform on which bCentral applications were based. After a short segue into on-premise core CRM functionality where the extension capabilities were disabled or hidden, the product is really progressing into a true platform.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;It'll be interesting to see what happens over the next two releases. One that's been talked about is called Titan and that's the one that I think of as the core platform. I'm looking forward to seeing what that team can provide to the rest of Microsoft, and possibly to the industry, in terms of platform. Watch out SharePoint, there's a new kid in town and that kid knows all about business application requirements.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1966408" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>Multiple forms per "entity"?</title><link>http://blogs.msdn.com/mikemill/archive/2006/06/14/631191.aspx</link><pubDate>Wed, 14 Jun 2006 21:06:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:631191</guid><dc:creator>mikemill</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/631191.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=631191</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=631191</wfw:comment><description>&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Why not? I was just thinking about &lt;A href="http://blogs.msdn.com/mikemill/archive/2006/06/13/629716.aspx"&gt;yesterday's post&lt;/A&gt; and had one of those disturbing thoughts that I get when I want to make software do something that its authors didn't intend (well, maybe, sorta, kinda). &lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Let's say I want to create multiple forms per "entity" (note the quotes). One way I might do this is to define a set of "like" entities in the metadata all pointing at the same physical location. I'd have to jury-rig the relationships a bit so the platform knew how to traverse them during create and update requests, but that's not really necessary.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;If I were going to do this, what would I do? I'd define several entities that all mapped to a single, all-encompassing (data-wise) entity, I'd hide the super entity using roles and privileges because we don't want anybody messing with all that data (for some reason Steve Martin saying "you could melt all this stuff" pops into my head right about now… I don't know why), and then I'd configure-up all the forms for the shadow entities. Finally, I'd rename all the shadow entities so they show up, more or less, in the application. Then, and here's where the per-role stuff comes in, define roles for each entity.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;In theory you should have different role-based views over the same set of data. Just a thought.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&lt;STRONG&gt;Update 13:45PDT&lt;/STRONG&gt; - If I were really going to do this I'd just copy all of metadata for the source entity to the destination entities. There's no reason to go through the pain of actually creating the physical tables. That's why CRM is metadata-driven - so you can define things declaratively and the system will do the rest.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=631191" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>Dealing with many 1:M CRM relationships</title><link>http://blogs.msdn.com/mikemill/archive/2006/06/13/629716.aspx</link><pubDate>Tue, 13 Jun 2006 19:54:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:629716</guid><dc:creator>mikemill</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/629716.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=629716</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=629716</wfw:comment><description>&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;I while back I mentioned in the CRM newsgroups that it was possible to create multiple relationships between two entities. For the most part this is true, but there are some hoops to jump through and each of those hoops is ringed in fire. More specifically, using this approach to solve the "many relationships" problem will plant you squarely in unsupported, probably-can't-upgrade, land.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;The problem I'm talking about is where you have a single parent entity - the 1-side, and you want more than 1 1:M relationship from that parent entity (let's call it P) to a child entity (smartly named C). Let's try an example. Say we have a Course that has an Author and an Instructor. Now, ignoring for a moment that CRM can't deal with additional party types and won't allow multiple relationships to SystemUser, we'll call Author and Instructor simply views over the same set of data. That is, they are the same entity with different roles.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;In CRM v3.0 you'd implement this by creating the three entities, setting up the Course-Author and Course-Instructor relationship, hiding the Instructor entity, and writing a callout to keep the Author and Instructor data in sync. That'll work and keep you supported. There are a few caveats that will cause some serious grief: you can't use the quick create functionality from an Instructor lookup, you need to keep the security consistent, and you can't completely hide the Instructor type as a separate type.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Well, there is a way around this. It's a hack but it's been successfully hacked for some internal development deployments. Create the three entities as you normally would but keep the child entities Instructor and Author "empty". Set up the relationships using the configuration tools. You now have three entities with two relationships much like you had in the supported approach. Now, customize both Author and Instructor in identical ways by adding all the attributes that the type needs. When you're done you'll end up with two identical entities pointing at two different database structures. You're still in supported land.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Do not add any instance data to either Author or Instructor yet.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Next, change all the display attributes for the Instructor entity so that it looks like an Author (this really isn't necessary and might make sense usage-wise if you treat them as different). Ready to jump into unsupported territory? Open the metadata database and find the Instructor entity (let's assume that Author is the primary view) in the Entity table. You'll see a few columns that describe physical table mappings for the core and extension tables. Change the table names to reflect that the Instructor entity should instead point at the Author tables. You'll want to make a few modifications to the Instructor attributes as well so that they reflect the underlying physical Author attributes (I think the primary key in the base and extension table is the only attribute you need to really worry about).&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Now, every time you add an Instructor or Author the data ends up in the same physical table. That means that any query over either entity will return the same set of data. So, your lookup control from Course to Author will present the same physical data as Course to Instructor. As far as CRM is concerned you have two different entities with two different relationships. You end up with copies of all the web service methods and the schemas will look nearly the same (their logical views will reflect the as-configured names, not the physical names). But, at a physical level you only have one copy of the data that you look at and edit, there are no synchronization issues, and there's no tricky callout code to handle multi-master updates.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;I might have missed a few steps here because I'm doing this from memory and not on a live CRM installation. If you find that some of the steps seem incorrect (missing, out of order, unnecessary) then post a comment here so everyone gets a chance to learn along with you.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=629716" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>Any uptake on the RSS connector for CRM?</title><link>http://blogs.msdn.com/mikemill/archive/2006/05/19/602158.aspx</link><pubDate>Sat, 20 May 2006 00:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:602158</guid><dc:creator>mikemill</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/602158.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=602158</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=602158</wfw:comment><description>&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Is anyone actively using the RSS connector CRM? If so, how are you using it and did you customize it any way? If not, what are the reasons for not using it?&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;This is really for my information. The CRM team might watch this space and have some desire to use the information, but that's not why I'm asking. My new team is looking at some related technologies and we're / I'm wondering how this one fit.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=602158" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category><category domain="http://blogs.msdn.com/mikemill/archive/tags/Web+2.0/default.aspx">Web 2.0</category></item><item><title>What is a "necessary evil"?</title><link>http://blogs.msdn.com/mikemill/archive/2006/05/02/588631.aspx</link><pubDate>Tue, 02 May 2006 23:26:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:588631</guid><dc:creator>mikemill</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/588631.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=588631</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=588631</wfw:comment><description>&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&lt;A HREF="/charle"&gt;Charles Eliot&lt;/A&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;stopped me in the café at lunch today and asked me to clarify &lt;A HREF="/mikemill/archive/2006/05/01/587976.aspx"&gt;my comments&lt;/A&gt; about why direct database access in MS-CRM is a necessary evil. Actually, I think I used the phrase "evil-but-absolutely-necessary" when I described the design and implementation of filtered views.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Way back when the CRM product was in design we had a few ideas about how the database should look. One camp took a very esoteric, but correct, view. The other had a highly normalized and simplified view. The latter design was chosen. One of the core tenets of that design was its inherent readability. Not necessarily readable by average users, but readable by people who'd have to write those "special" reports that the system didn't provide.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;Why does this matter? Well, because the idea was that the database should be accessible and not locked away. I always believed, and still do, that the data and the database belong to the customer and they can do damned near anything they want.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We wrapped the database in a user-protective layer called the CRM platform and asked that anybody wanting to write to the database go through that layer. We never said you couldn't read directly from the database though.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;What we did say, although I suspect the written word is a little light, is that we reserve the right to modify the data structures on a release-by-release basis to provide greater functionality, faster access, bug fixes, and so forth. I even went so far as to say that we would break any application written which bypassed the platform layer, and I said it in public several times.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;With the release of 3.0 and the exposure of filtered views we still reserved the right to break any application written on those views. Only, in this case, because we released the bits as a "feature" and then started talking that same feature up, we got ourselves into a situation where breaking applications isn't a great idea. In short we said "go ahead and use the filtered views, they're good for you". But, we didn't look far enough into the future to see what effect that would have on innovation.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;So, I stand by my comment. The filtered views, and by extension direct database access, is an evil-but-absolutely-necessary thing. It can't go away. It probably can't even change significantly. But, I expect those views to morph over time as &lt;A HREF="/mikemill/archive/2006/04/11/573522.aspx"&gt;new schema concepts&lt;/A&gt; are introduced.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-STYLE: italic; FONT-FAMILY: Calibri; mso-outline-level: 1"&gt;On continuous loop for the last few days is &lt;A href="http://www.amazon.co.uk/exec/obidos/ASIN/B000EJ9KJE/qid=1146600700/sr=8-1/ref=sr_8_xs_ap_i1_xgl/202-8203675-5443843"&gt;Zero: A Martin Hannett Story&lt;/A&gt;. It's a must listen for any fan of Mancuncian music from the late 70s and early 80s.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=588631" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>New CRM blog and blogger</title><link>http://blogs.msdn.com/mikemill/archive/2006/05/01/587976.aspx</link><pubDate>Tue, 02 May 2006 02:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:587976</guid><dc:creator>mikemill</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/587976.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=587976</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=587976</wfw:comment><description>&lt;P&gt;&lt;FONT face=Tahoma size=2&gt;Note: free exposure to CRM team members' blogs.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Tahoma size=2&gt;Charles Elliot, a good friend and recently a co-worker of mine, has finally jumped into the &lt;/FONT&gt;&lt;A HREF="/charle/"&gt;&lt;FONT face=Tahoma size=2&gt;blogging world&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Tahoma size=2&gt;. Knowling Charles I'm expecting a lot of goodness to come our way. In particular, I'm waiting for him to start talking about music and his take on it.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Tahoma size=2&gt;In other news, the CRM PM team has a new &lt;/FONT&gt;&lt;A HREF="/crm"&gt;&lt;FONT face=Tahoma size=2&gt;blog&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Tahoma size=2&gt;. I suspect they'll stay pretty much in the "supported" world and will talk to you about all things CRM V3 and what they're planning for future releases. As I've been steering clear of the CRM world for a few months now I'm not sure what goodies they'll talk about first (although I see Charles has posted something about the, IMO evil-but-absolutely-necessary, direct database access exposed in V3). It'll be very interesting to see what the CRM PM team blogs about that's not blogged about on&amp;nbsp;other CRM PM team member blogs.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=587976" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>Announcing the RSS connector for MS-CRM 3.0</title><link>http://blogs.msdn.com/mikemill/archive/2006/03/24/560334.aspx</link><pubDate>Sat, 25 Mar 2006 00:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:560334</guid><dc:creator>mikemill</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/560334.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=560334</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=560334</wfw:comment><description>&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;We've finally &lt;A href="http://download.microsoft.com/download/3/2/1/32163234-b67e-491b-ae5a-8717f649baaa/CrmRssFeed.exe"&gt;released&lt;/A&gt; the RSS connector for MS-CRM. I've mentioned this&amp;nbsp;&lt;A HREF="/mikemill/archive/2005/09/20/472020.aspx"&gt;tool&lt;/A&gt; a few &lt;A HREF="/mikemill/archive/2006/03/02/542387.aspx"&gt;times&lt;/A&gt;.&amp;nbsp;This has been a long release &lt;A HREF="/mikemill/archive/2006/02/17/534191.aspx"&gt;mired&lt;/A&gt; in a few documentation, legal, and technical issues. But, that's not your concern, you probably just want to download this thing, install it, and make things happen. Well, here's the backgrounder on what's making the connector tick. The MSDN article which comes with the connector download covers some basic information. Look for a longer whitepaper from our UE team in the next few weeks.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;We want to hear how you've used, modified, or extended the connector. If you use it, let me know. This is the last bit of code that I built for the CRM team (well, it's the last bit that I released, I was still working on the add-entity framework and address book right up to RTM) and I'd like to see what happens with it (and no, this isn't typical of the code quality that I usually write, this was a prototype first and a public release second; if we were going to release this is would be very different). We're releasing this under a different model (see the EULA) and we're very interested in its life once it leaves here.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Basics of the connector&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;The RSS connector for CRM is built on top of the advanced find and web service Fetch functionality. For the most part it directly executes the requested query and returns the results as RSS-formatted XML. However, there are a few changes that are made to the base query (if you're wondering, all queries are stored as serialized &amp;lt;fetch&amp;gt; requests, which means the connector gets to mess with XML). &lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;First thing that happens is that the connector loads the actual &amp;lt;fetch&amp;gt; definition for the requested user or system query. Next, it creates an array of the columns specified in the query's grid. These are used for specifying the &lt;A HREF="/rssteam/articles/SimpleListExtensions.aspx"&gt;simple list extension&lt;/A&gt; attributes for IE7 sorting and grouping. The one change from the grid columns is that the connector adds the &lt;SPAN style="FONT-STYLE: italic"&gt;modifiedon&lt;/SPAN&gt; attribute if it's part of the underlying entity's definition.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Once the connector has cached away the display attributes it modifies the in-memory copy of the query so that all attributes are available. The query definition has all of its selection criteria removed as well so that the feed data is as broad as possible given the caller's security attributes.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;User queries vs. system queries&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Under the covers system queries and user queries are structurally the same. They are stored in different tables in the database (don't ask, it was a decision that couldn't be undone by the time it was noticed), they have the same columns, and they have the same semantics. The primary difference is that the security model changes: system queries are effectively public and user queries are effectively private. A secondary difference is that they had different APIs during the TAP and alpha releases because they just happen to be written in two different languages (again, don't ask).&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;This does have the nice side-effect that the RSS connector simply reads the query definition through the proper entity. It's really just a &amp;lt;fetch&amp;gt; that changes entity names and some minor decorations.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;When the RSS connector displays the nice HTML-based list of available feeds it does so in two sections. The top contains user-specific feeds and the bottom contains all accessible system feeds. The connector also generates HTML &amp;lt;link&amp;gt; elements for each user query. This tells RSS-aware browsers and readers that there are feeds published on the page. The connector only does this for user queries otherwise the list would be unreasonable long.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;How the connector selects attributes for display&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Because the connector modifies the query definition to force all attribute selection (this isn't just done for display, it's also done to support instance delivery, but more on that in a minute) it's able to present a rich view of the instance data to the RSS aggregator. In WriteItemData the connector loops over the entity's attribute list in a semi-intelligent order. It writes the primary field, any audit attributes, any state or status attributes, ownership data, any "description" attributes, and then all the rest. Nearly all attributes retrieved from the platform are displayed: there are a few attributes that have no public view and no reasonable display label, so those are skipped.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Riding on coattails - using the list extensions&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;The connector uses the query's grid column to select the set of attributes used in the list extensions elements. Technically, this is a de-selection, because the connector rewrites the query to remove the attribute list and adds an &amp;lt;all-attributes&amp;gt; clause to the &amp;lt;fetch&amp;gt;. In the foreach loop in WriteCrmAttributes there's a check to see if the "current" attribute is in the cell list and if it's not it's skipped. The data is written in a manner that makes list extension display useful to the user and executable to the extension processor. That is, all "codes" and other internal details are tossed away and nice display values are used instead.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;The lightweight metadata cache and the service proxy&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Two things that held up earlier release of the connector were technologies that I used to make the connector happen but which aren't supported outside of the CRM team. These are use of the 1.2 COM proxy (which is finally gone in the upcoming CRM release - I hated that thing because I had to code it over my wife's birthday a few years back and that got me in a lot of trouble) and the internal metadata cache assemblies.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;I didn't want to freak out our development team so I had to use the same metadata interfaces that everyone else uses. The problem is that the MD web service delivers too much data too slowly for me (speaking of slow, one optimization I'd like to see in the connector is to read the queries in one batch instead of on a per-entity type basis). To get around the metadata problem I rolled a very lightweight and purpose-built cache that uses the web service to read the metadata and keep it around in a static. There are a ton of problems with this approach: there's another copy of the cache floating around and CRM is already memory-hungry, and this cache isn't aware of customization changes (i.e. Publish) so it can get out of sync. I didn't consider either of these show-stoppers for this add-on, but the PM in charge of programmability does and he's doing something about it for V.next.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;One thing that I did that might be a little surprising was that I asked for the WSDL and then hand-edited down to its absolute basic bits for this solution. I didn't want a 650Kb proxy loaded into the connector and I didn't want the connector to pay the late compilation and reflection hit when W3WP loaded the proxy. The connector only uses the Fetch method and the SOAP header. That means I was able to strip all the types and method definitions out (sorry Kevin and Arash). And no, I'm not using this as an apology for the web service shape in V3, it's a good thing. I didn't have to do the same thing with the metadata proxy because it's fairly small and the connector needs a lot of the definitions from it.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;If you've gotten this far make sure you read my entry on using the offline client hosting process otherwise known as Cassini. I used the connector to verify that I could make the offline client web services work.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Optional non-IE7 "list extension" behavior&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;When the RSS feeds are displayed to the user there are two RSS icons and a text-based hyperlink. The two icons represent the "simple" RSS feed and the RSS feed with the complete instance data. The text link will show a down-level IE representation of the IE7 RSS viewer. This bit of code is a very early prototype put together by the IE and RSS team to show what the IE7 experience might look like. I lifted the code from those teams for the PDC demo and just never got around to removing it. Someone better versed in cross-browser AJAX stuff might be able to make this work better in other browsers. For now, this link can be ignored (and I would recommend replacing the link with the "real" RSS link and let the browser figure it out).&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Delivering a complete CRM instance in the &amp;lt;item&amp;gt; data&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;The RSS connector has the capability to deliver, as part of the item data, the XML serialized representation of a complete entity instance. It does this to enable a set of scenarios supported by &lt;A href="http://spaces.msn.com/rayozzie/Blog/cns!FB3017FBB9B2E142!175.entry"&gt;really simple sharing&lt;/A&gt; and by some hub and spoke delivery models that we're looking at. When this option is enabled the &amp;lt;channel&amp;gt; element contains the underlying entity's XSD (this is a different XSD generation process than the WSDL uses). When a smart RSS aggregator loads a feed with the CRM namespace it knows that the entity definition and entire entity instances are available to it. This means you can tunnel select CRM instance data over RSS without exposing the CRM web services. RSS provides the pipe through which this data moves. We've come up with dozens of applications for this delivery mechanism and will start building some software based on this model over the summer. (This is the project that I've left the CRM team to work on and I couldn't be more excited about it.)&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Wrapping things up&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;The rest of the code is just infrastructure used to make CRM data into RSS. It's missing support for HTTP 304 and ETags. I'm hoping that someone will add that and drop me an update so I can reverse-integrate it into the code. I'm assuming that the connector will fall under the "unsupported sample code" umbrella which means that there isn't a formal support infrastructure in place for it. However, if you post a comment to this entry I'll see that they get to someone in the CRM team.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;Building and installing the connector is easy. I'm assuming that the MSDN document talks about this, but if it doesn't here's the short and sweet. With the connector code is a small CMD script that if executed from a VS2003 command window will compile and copy the assembly to the bin directory. My demo installation uses the ISV extensions to add a "Web feeds" item to the menu which points at the RSS feed display and a convenient OPML page. There's a 16x16 PNG file that fits nicely in the menu and just happens to match the IE7 and Firefox RSS icons.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;More things to read&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&lt;A HREF="/mikemill/archive/2005/09/20/472020.aspx"&gt;RSS and CRM - a little history&lt;/A&gt;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&lt;A HREF="/mikemill/archive/2006/02/17/534191.aspx"&gt;Where is the RSS connector for CRM 3.0&lt;/A&gt;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&lt;A HREF="/satyanadella/archive/2005/09/13/465381.aspx"&gt;“Democratizing” Business Logic and Data&lt;/A&gt;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&lt;A HREF="/rssteam/articles/SimpleListExtensions.aspx"&gt;Simple List Extensions&lt;/A&gt;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&lt;A href="http://spaces.msn.com/rayozzie/Blog/cns!FB3017FBB9B2E142!175.entry"&gt;Really Simple Sharing&lt;/A&gt;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&lt;A HREF="/mikemill/archive/2006/03/02/542387.aspx"&gt;Using the CRM SDK offline&lt;/A&gt;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; FONT-FAMILY: Verdana; mso-outline-level: 1"&gt;&lt;A href="http://download.microsoft.com/download/3/2/1/32163234-b67e-491b-ae5a-8717f649baaa/CrmRssFeed.exe"&gt;Microsoft Dynamics CRM RSS Connector&lt;/A&gt;&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=560334" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category><category domain="http://blogs.msdn.com/mikemill/archive/tags/Hybrid+models/default.aspx">Hybrid models</category><category domain="http://blogs.msdn.com/mikemill/archive/tags/Web+2.0/default.aspx">Web 2.0</category></item><item><title>Inside MS-CRM goes Outside</title><link>http://blogs.msdn.com/mikemill/archive/2006/03/07/545439.aspx</link><pubDate>Tue, 07 Mar 2006 20:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:545439</guid><dc:creator>mikemill</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/545439.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=545439</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=545439</wfw:comment><description>&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;It all started with an email to a few guys working on a replacement lead management solution for MSN. The point of that email was that we could change the way software was built and create a new model for our partners around linking software to services in the clouds. Wow, now that I look back on it, that seems like a long time ago. Funny thing is that reading that email today brings back lots of memories of being very excited about being on the brink of something huge. When I read that email again last week while dusting off my office I realized that the excitement is still there. It's just shifted a bit for me.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;The MS-CRM team has grown and changed over the last (nearly) seven years and I'm glad I was a part of it. I think the team set out to build something and after a few fits and starts actually outdid itself. We learned a lot on the way - both good and bad. I've grown and changed a lot over those same years. I've filled three roles on the CRM team: architect, developer, and overall pain in the butt. To any of those folks who dealt with me while I was on a rampage I apologize.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;My decision to leave the team really didn't come as easily as a lot of people might think. There's a lot of cool work to be done on the product and I wanted to be part of that. However, I leave the product in very capable and caring hands. I trust them to do the right thing and I trust that they'll probably bounce their ideas off me on occasion just to see what the old guy says.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;You know, it's kind of funny. I actually thought that MS-CRM would be the last team I'd work on at Microsoft. I really believe that the product has a future and I think the environment in which it sits today will start to adopt some of the principles that we put into the product. There were a few times where I figured this would be my last Microsoft job because I wasn't going to find anything else cool to work on. Yeah, I know, it sounds weird what with all the things that Microsoft does, but I couldn't find anything else I wanted to work on.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;For the foreseeable future… or the next year, whichever comes first… I'm going to be working on hybrid line of business applications. One of the things I'd like to do is go back to the vision in that original email and see if we can tie all the goodness that is MS-CRM with a bunch more goodness in the clouds. So, I guess I'm going to start looking at MS-CRM as an ISV… from the Outside.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;This is going to be pretty damned cool.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=545439" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category><category domain="http://blogs.msdn.com/mikemill/archive/tags/Randomness/default.aspx">Randomness</category></item><item><title>Using the CRM SDK offline</title><link>http://blogs.msdn.com/mikemill/archive/2006/03/02/542387.aspx</link><pubDate>Thu, 02 Mar 2006 23:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:542387</guid><dc:creator>mikemill</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/542387.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=542387</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=542387</wfw:comment><description>&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;I've been meaning to write something about using the CRM SDK in an offline state, and I've been meaning to write it for a few years now. I guess I never had the right prodding, but recent newsgroup posts show that there are people interested in this, and that they're stuck.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;So, I started doing a little playing around to see what might happen. First thing I noticed is that, as expected, if the client isn't in an offline state you can't work with the local web server. There's code deep in the platform security layer that flat out stops the calls. Ok, that's easy enough to do - let's put the client in an offline state for a while and see what breaks next.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;I needed an "application" to test with and I just happened to have my RSS feed generator bits handy and hot off the press. They're really simple and use a very narrow set of CRM SWS (what we call the web service) methods. In fact, it only uses Fetch() to do all of its magic (oh yeah, and it uses a ton of metadata, but that's another posting). Well, as many of you have noticed, you can't get reasonable WSDL from the offline SWS because the module that generates our WSDL (which happens dynamically if you're wondering) isn't on the client. There's just no need for it there.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;I pulled WSDL from the server endpoint and hand-tweaked it so it had just the API set that I needed. This isn't strictly necessary, but given the size of the generated code and number of classes there's a significant hit to start-up performance as the CLR reflects over all those types. Anyway, all I needed was Fetch() so I removed everything else and compiled up the resulting CS file into a client proxy assembly.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;After installing everything I thought I'd need to run my application offline I noticed that there was a problem hitting the SWS in Cassini, particularly around executing queries. In this case the thing to remember is that queries are old V1.x functionality and that they're implemented in native C++. That means the SWS needs its own proxy to get at those C++ bits. That's where the COM proxy comes in (warning: the COM proxy has already been removed from the next release's build environment, so don't assume you can use this in any supported way for anything).&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;You might have noticed that the COM proxy isn't on the client machine anywhere (although there is another client-specific COM proxy, but that's not the one we want for this exercise). Go to your install CD or grovel the COM proxy from somewhere off your server and copy it to the res/web/bin directory on the client. Then, and this is important, GAC it so it's accessible from the Cassini process.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;That's all I needed to do to get arbitrary query support on the client in a custom application offline. I haven't expanded to arbitrary reads through other messages, but I'm assuming that they should all work. I also haven't done anything with create / update / delete yet because those requests must end up in the playback queue. The COM proxy doesn't do this work. If I remember correctly, this happens somewhere in the RC proxy or in Cassini itself (it would make the most sense for this to work as an HTTP handler inside of Cassini since we want to capture SOAP requests for later playback).&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Anyway, I hope that unblocks a few creative people and gets them moving in a direction that helps. I'd love to start seeing some add-on code running in an offline state. Granted, things like callouts and workflow won't work offline, so don't even both trying to make them work.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;If anyone comes up with a cool offline add-on I'd like to hear about it.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=542387" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>RSS connector revisited</title><link>http://blogs.msdn.com/mikemill/archive/2006/02/23/538235.aspx</link><pubDate>Fri, 24 Feb 2006 02:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:538235</guid><dc:creator>mikemill</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/538235.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=538235</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=538235</wfw:comment><description>&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;I'm getting close to finishing the &lt;A href="/mikemill/archive/2006/02/17/534191.aspx"&gt;RSS connector&lt;/A&gt; now. I've finished the cache code and I've switched the query engine over to use the CRM 3.0 web services. I'm not sure how we'll release this, but I suspect it'll be part of the CRM GotDotnet sandbox somewhere. Stay tuned.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=538235" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>Where is the RSS connector for CRM 3.0</title><link>http://blogs.msdn.com/mikemill/archive/2006/02/17/534191.aspx</link><pubDate>Fri, 17 Feb 2006 20:11:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:534191</guid><dc:creator>mikemill</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/534191.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=534191</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=534191</wfw:comment><description>&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;It's stuck in LegalLand right now. It's not really Legal's fault either. When I put the original prototype together for the BizSummit and PDC I was able to take liberties with the set of APIs that I used. Yup, I ended up using unsupported functionality. Shouldn't be much of a surprise, I have access to all the internals, I'm on the team, I needed to get a job done, and this blog has always been about &lt;A HREF="/mikemill/archive/2005/09/19/471414.aspx"&gt;pushing&lt;/A&gt; &lt;A HREF="/mikemill/archive/2004/12/01/273258.aspx"&gt;past&lt;/A&gt; the &lt;A HREF="/mikemill/archive/2006/02/14/532121.aspx"&gt;envelope&lt;/A&gt;.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Turns out that once the connector was public the demand went way up and the internal pressure to release it went up. Problem is there's no dedicated resource for "fixing" the bits that I cheated on. That means that we (read that Microsoft) can't release the connector without doing one of two expensive things: document the undocumented or fix the code.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Ideally I'd like to fix the code. I really didn't push the envelope all that much. In fact, all I did was cheat a bit and use the COMProxy instead of the shiny new SWS (of which I am a long-time champion) for tweaking the requested queries, and I directly access the application-level metadata cache. Fixing the COMProxy issue is an afternoon's worth of work. It really just means pulling the WSDL, ripping out all the bits that have no bearing on RSS (so it loads faster), and tweaking a few query functions. The metadata cache is another issue altogether.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Here's why. The application-level metadata cache has two nice properties: it's already loaded and can be shared with the application thus cutting down on memory requirements, and it has a reasonable object model (note that I didn't say it has a good object model… if it did we would publish it). That means I need to define an object model that makes sense, and I'd want to make it "big enough" to be useful. Plus, I would need to write a bunch of code to read the WS-based metadata data and transform that into the nice object model. I've been assuming that anything I do in that space, once released, will probably end up in general usage (I would actually hope so because I wouldn't want everyone to have to go through this same pain). If I'm right about that then I would want to make sure that the cache is really usable. But then that means I'd need to spend more time "getting it right". There's also the added problem that if I, as an aside, release a metadata cache programming model that people will come to expect something much like it in a future product release (which is why I never made the &lt;A HREF="/mikemill/archive/2005/02/15/373344.aspx"&gt;1.2 web service code&lt;/A&gt; generally available - when I was finally ready to release it the product team took up the banner and built one themselves).&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;If there really is demand for the RSS stuff and / or the an object-based metadata cache, let me know and I'll try to get it on the radar. If not, let me know and I'll keep working on other things.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=534191" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>CRM metadata browser</title><link>http://blogs.msdn.com/mikemill/archive/2006/02/14/532121.aspx</link><pubDate>Wed, 15 Feb 2006 01:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:532121</guid><dc:creator>mikemill</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/532121.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=532121</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=532121</wfw:comment><description>&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'"&gt;

It was interesting to see Mitch Milam's &lt;a href='http://blogs.infinite-x.net/?p=27'&gt;post&lt;/a&gt; about the metadata browser. This was a little tool I put together pre-V1.0 ship, but which didn't make the schedule until V3. Mitch points out the "published" component which displays the entity metadata in a nice format. If you edit list.aspx you'll see two sections commented out that provide links to individual entity schemas. This is unsupported and undocumented functionality that we considered calling "sample code". Turns out that it made it into the box but not enabled by default. These schemas work nicely with the &lt;a href='http://www.microsoft.com/downloads/details.aspx?FamilyID=89e6b1e5-f66c-4a4d-933b-46222bb01eb0&amp;DisplayLang=en'&gt;code generators&lt;/a&gt; that I &lt;a href='http://blogs.msdn.com/mikemill/archive/2005/02/15/373344.aspx'&gt;blogged&lt;/a&gt; about a while back.

&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=532121" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>Why duplicate detection is hard</title><link>http://blogs.msdn.com/mikemill/archive/2006/02/07/527052.aspx</link><pubDate>Wed, 08 Feb 2006 02:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:527052</guid><dc:creator>mikemill</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/527052.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=527052</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=527052</wfw:comment><description>&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;In a past life (I'm fairly certain it was a past life because there are days when I'm sure I'm paying for it), I worked on a pair of very large-scale data-cleansing systems. They will go unnamed, except that I'll refer to them as System DBS and System ES. Both systems had a specific set of goals and in the case of DBS a very specific target problem domain. The goals were quite simple:&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;UL style="MARGIN-TOP: 0in; MARGIN-BOTTOM: 0in; MARGIN-LEFT: 1in; DIRECTION: ltr; unicode-bidi: embed" type=disc&gt;
&lt;LI style="MARGIN-TOP: 0px; FONT-SIZE: 10pt; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; COLOR: maroon; mso-outline-level: 2"&gt;&lt;SPAN style="FONT-FAMILY: 'Eras Medium ITC'"&gt;Acquire data from a number of related applications (where "related" is a very loose term meaning that the owning company for each application was effectively the same, but that otherwise they supported different business functions).&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="MARGIN-TOP: 0px; FONT-SIZE: 10pt; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; COLOR: maroon; mso-outline-level: 2"&gt;&lt;SPAN style="FONT-FAMILY: 'Eras Medium ITC'"&gt;Define a common schema that captures the union of all the source data.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="MARGIN-TOP: 0px; FONT-SIZE: 10pt; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; COLOR: maroon; mso-outline-level: 2"&gt;&lt;SPAN style="FONT-FAMILY: 'Eras Medium ITC'"&gt;Define the set of candidate keys that lets you identify an item's source, its original key, its common key, and its goal key.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="MARGIN-TOP: 0px; FONT-SIZE: 10pt; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; COLOR: maroon; mso-outline-level: 2"&gt;&lt;SPAN style="FONT-FAMILY: 'Eras Medium ITC'"&gt;Construct from that data a common union of all interesting elements. That is, load it all up.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="MARGIN-TOP: 0px; FONT-SIZE: 10pt; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; COLOR: maroon; mso-outline-level: 2"&gt;&lt;SPAN style="FONT-FAMILY: 'Eras Medium ITC'"&gt;Apply a forward-chaining rule system over that data to coalesce duplicate records, identify "bad" data, any find missing data.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="MARGIN-TOP: 0px; FONT-SIZE: 10pt; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; COLOR: maroon; mso-outline-level: 2"&gt;&lt;SPAN style="FONT-FAMILY: 'Eras Medium ITC'"&gt;Push that nice clean data back out into the bad dirty world from which it came (but put it back nicely)&lt;/SPAN&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in 0in 0in 0.5in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 2"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Given that DBS was specifically designed to run over data from a given problem domain (let's call it telecom data) one might assume that the problem was well-constrained. If one did assume that one would be very wrong. So, a small team of developers set out to generalize the problem space to cover different domains and designed ES as a result. ES followed the same path as above only in a very general way and without the overly complex rules engine (12 years later I think we might have been able to use that rules engine, but at the time our distaste for it was clear in the ES design). As an aside outside of parentheses this was called the U model mainly for the shape that the model took on while we drew it on the whiteboard.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;So, what's the point of that history lesson and what does it have to do with duplicate detection. Well, remember that I mentioned that the primary domain was telecom. That means we covered concepts such as customers, addresses, telephone numbers, physical plant data (there are a lot of little pieces that go into getting telephone service over a land line), bills &amp;amp; invoices, and payments. In all there were some 30 different systems involved in sourcing this data to our engine. One the first things that needs to happen in the DBS problem space is that a set of candidate keys need to be identified that work across all systems, or at least across enough systems such that in the end all systems can be logically linked. In the telecom world that was the phone number.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;In the U.S. (actually in the North American dialing area) telephone numbers are 10 digits long and always follow a very specific format. I won't go into the formal names for those various groups of digits or even why there are groups, but let's just say that each of the groups can become part of a key. Nearly every installation of DBS was in the U.S. so building a telephone number parser wasn't too terribly difficult. You're either looking for 7 or 10 digits (unless you run across a PBX in the data and then you have to start messing about with extensions). Well, the big DBS installation I worked on, and what drove much of the ES design, was not based in the U.S., but was instead in another country with very different telephone formats. Some places used 4 digits, some 5, some 7… you get the point. The plan was to configure and run DBS to first dedup that data so we could convert the whole country to 10 digit dialing. A secondary goal, once the customer realized what we could do, was to dedup the whole lot of data to see what we could find (did you know that many times the phone company doesn't know that your home already has a connected telephone line so they sent a technician out with new gear to hook it up?).&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;I can hear you now: "Get on with the discussion and tell us why duplicate detection is hard."&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Remember that I mentioned the step about identifying a candidate key? Well, in the case of a phone number it's fairly simple (let's make some additional simplifying assumptions that phone numbers are never reused, each person has only one phone number, and numbers never move from person to person). Once you see a phone number in a normalized format you can then query over the set of existing data looking for other instances of that phone number. In a live RDBMS that can be done using a unique key constraint over the normalized phone number column that will throw back an error when an insert or update attempts to violate that key. In our simple world this works every time because when you get an error on an insert you know that you have either a duplicate record or an error in the key. For updates you know you have an error in one of the keys of the updated record or in at most one existing record in the database.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Now, let's extend this from our idealized phone number world to something that's more CRM-ish. A phone number is not a reasonable candidate key because it does change over time, two people can share it, and many people have many numbers. A solution to this problem is to identify a new candidate key. One approach is to construct a key from various bits of useful information. For example one might use some normalized elements of a contact's name, a phone number, possibly an email address, and their home address. Once we've extended the key to cover enough elements to guarantee uniqueness (which is not possible and is left as a proof to the reader) in our problem space we will invariably run into the case where that key isn't wide enough. &lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Let's see what happens when we insert a new record. First, we construct / synthesize a candidate key and put it into one of the columns in the INSERT statement. Then we fire the statement at the database and wait for an error. Let's assume we get a key violation back so we have a few options: we can change the key, we can ask the data supplier what to do, or we can punt. If we change the key automatically then we've simply ignored the duplicate detection problem and we might as well not have done any of this work. Same thing with punting except that it's overly harsh on the other side: the data doesn't go into the database.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;We might ask the user what to do. Well, simply telling them that their just-entered data would create a duplicate record in the system and therefore must be in error wouldn't be particularly useful. How would they know what part of it is in error? How would they even know what to do with a duplicate. One thing that DBS and ES did was return the new record and the existing duplicate(s) in a nice bit of dynamic UI so that the user could see both records essentially side-by-side and make a judgment call. This worked for our solution because we specifically engineered it so that there was a headless service running but a staff of "Error Resolution and Correction Clerks". That is, people were sitting in the dark waiting for bad data to pop up on their screen, they'd make a call based on the original data, the duplicate data, and occasionally the data from the source system.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Let's say we do something like the first approach where we simply return the "offending" records and the new record and let the user decide. Then, the user decides that these two records are actually different from one another but that the data is 100% correct. In this case the user or the system could mar the record in such a way that it's no longer considered a duplicate and complete the write operation. What just happened here? Well, the candidate key for the new item will no longer raise an error when it's the cause of a duplication because that key is different. We could mar the data in a predictable way so that the key stays intact but so that there's a "larger" unique key over the data, but again that wouldn’t cause the insert to fail.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;The next option is to use a unique key over the candidate key plus some invented data (invented in a predictable way that is) and query the data on the candidate key before attempting an insert. Now we're getting somewhere. We allow duplicate candidate keys but invent a wider key that guarantees uniqueness (see above for details on the widening proof). But we still haven't solved the problem because we don't have a reasonable way to verify that a duplicate is really a duplicate.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;This all gets horribly complex when you're dealing with multiple record types or subclasses of types (think of the customer case in MS-CRM where "customer" might mean Account or Contact. This means you need a candidate key that crosses type boundaries and that you have a way to reconcile duplicates across types.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Anyway, that's why duplicate detection is hard. Note that I didn't say it was impossible, just hard.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=527052" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>The "F" in the DMF</title><link>http://blogs.msdn.com/mikemill/archive/2006/02/07/526833.aspx</link><pubDate>Tue, 07 Feb 2006 21:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:526833</guid><dc:creator>mikemill</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/526833.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=526833</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=526833</wfw:comment><description>&amp;nbsp; 
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;[Note: This is personal opinion, it doesn't reflect the viewpoint of Microsoft or the Microsoft CRM team. This is my take on the DMF and both its shortcomings and ultimate potential. Don't assume that anything that seems like a prediction here is apt to happen. I'm only peripherally involved with the DMF team and I don't set direction for them.]&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;It's a Framework&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;The "F" in DMF is all about frameworks. Why? Because creating a general-purpose data migration tool or product is extremely difficult, expensive, error-prone, and unlikely to meet our customers' needs. That's right. The DMF is a framework because that's the best approach we could take and the most we could provide without setting unrealistic expectations. Simply put, there isn't a way for us to create a tool that can detect all possible data formats from all possible CRM "applications" and correctly get that data into your shiny new (or slightly used) MS-CRM without the potential for serious data disaster.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Let's look at a few scenarios to see why the framework approach was recommended and pursued by the R&amp;amp;D team. First, we can assume that existing CRM systems have been customized (I don't have the exact numbers, but my gut tells me that it's a high percentage). Next, we can assume that a CRM system has been in use long enough to collect a reasonable amount of data (otherwise why would we worry about migrating data from an existing system to a shiny new MS-CRM).&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Given that an existing system has been customized and has been running for some time there's likely to be a few "dirty" bits of data floating around. That doesn't mean that there's a bug with the in-place system. By "dirty" I simply mean that the data in any given database column will have both syntactic and semantic problems. For example, in the U.S. states are typically abbreviated to two uppercase letters. But that hasn't always been the case. For example, Minnesota is conventionally abbreviated MN (at least that's what the post office would like to see), but it's conceivable that collected data includes other abbreviations like "Minn.", misspellings, fully-specified values, and even missing data.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;That's just one simple case. Phone number formats and addresses are notoriously hard to agree upon. More about that particular problem in a few days when I get around to talking about why duplicate detection is actually damned difficult to do well.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;What we wanted to provide and what we did provide&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Ideally we would like to have shipped something with a lot less user-facing emphasis on the "F" part of DMF. One of our goals, which we simply didn't meet, was to provide a Big Green Button that when pressed would discover your other CRM data, clean it up, normalize it, automatically match it to your new MS-CRM system (including all the customizations you put in place and any others that we might discover while migrating your data), and last, but not least, migrate that data. Really, that's what we wanted to do. [Bobert, if you're reading this you'll remember working on another system just like this about 10 years ago and about 9000 miles away.] Well, we didn't ship one of those, so what did we ship?&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;The general idea behind the DMF is that you're not migrating a single system just once. You might be in which case the DMF still provides a ton of value. One of the assumptions that we had was that MS-CRM customers would be migrating from any number of essentially unknown systems. So, without some really great AI we would need a bit of manual intervention. That is, we'd need to ask a number of questions about your data: what format is it, what source systems hold it, what are the syntactic modifications, and what semantic rules are applied. In many cases we assumed that at least the latter two questions couldn't be answered directly: you would need to discover those rules as you went.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Why is this a multi-step process&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;It was precisely this problem that drove the idea of the intermediary staging database - the CDF. The idea here was to incentivize&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;partners to either create adapters from source systems for resale (i.e. connect the CDF to Act or Goldmine) or to build a consulting business model around migrating custom data (Access databases, Excel files). We would provide the back-end services such as constructing the CDF from your customizations and moving the data into your production system. &lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;There were three huge problems with this model: we didn't get the partners we wanted; we didn't provide a key piece of technology; and we didn't get the CDF construction logic completed. In retrospect I think the partner model would have been easier to sell if we (and the partners) were up-front about including data acquisition, cleansing, and migration costs directly in the CRM purchase price. Not doing so left the customers with an unexpected bill for these services. We missed the key data cleansing middleware that would have taken all the source data, applied a set of cleansing rules, and produced useful production data. The problem is simply that the technology is extremely hard to get right and even when it is right still requires a set of domain-aware eyeballs to verify the production rules. Finally, we could have and should have done a better job reading your customizations (pick lists and pick list value mappings in particular) and applying them to the CDF and the cleansing / mapping rules.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-WEIGHT: bold; FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;What's next for the DMF?&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;That's a good question. I know where I'd like to see the DMF go in future releases, but I can't promise that the team has the same point of view. In particular I think we can do a lot better job in the back-end CDF construction; we can do a much better job with value maps; we should be able to better manage keys; and we should do a better job and basic data cleansing. This latter bit is the most important in my mind: without clean data the value of your CRM system rapidly deteriorates. This isn't just a DMF problem, but if we could verify that source data, once scrubbed, met certain criteria, we would be a lot closer to helping with the problem.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;Another area that the DMF could stand some improvement in is around managing multiple phase migrations. The idea of the DMF works great for one-time migrations where all the source data from all the source systems is moved into the CDF at the same time. It doesn't necessarily help if the data is moved in piecemeal unless the DMF includes basic rules around duplicate detection, prevention, and clean-up. If the CDF holds source data over time we can get closer to solving the problem because we can identify these issues during clean-up and "do the right thing." However, if the CDF takes on more of a bulk-load / bulk-import role as a staging area then the actual import step from CDF to CRM needs to include reasonable rules covering data clean-up rule application at the platform level. That's another topic for another day though.&lt;/P&gt;
&lt;P style="FONT-SIZE: 10pt; MARGIN: 0in; COLOR: maroon; FONT-FAMILY: 'Eras Medium ITC'; mso-outline-level: 1"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=526833" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item><item><title>3.0 SDK is now live on MSDN!</title><link>http://blogs.msdn.com/mikemill/archive/2005/12/16/504755.aspx</link><pubDate>Fri, 16 Dec 2005 21:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:504755</guid><dc:creator>mikemill</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/mikemill/comments/504755.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mikemill/commentrss.aspx?PostID=504755</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mikemill/rsscomments.aspx?PostID=504755</wfw:comment><description>&lt;p style="font-size: 10pt; font-family: Arial"&gt;This just showed up in my inbox. Enjoy!&lt;/p&gt;

&lt;p style="font-size: 10pt; font-family: Arial"&gt;
&lt;strong&gt;From:&lt;/strong&gt; Amy Langlois &lt;br&gt;
&lt;strong&gt;Sent:&lt;/strong&gt; Friday, December 16, 2005 9:30 AM&lt;br&gt;
&lt;strong&gt;To:&lt;/strong&gt; CRM Team&lt;br&gt;
&lt;strong&gt;Subject:&lt;/strong&gt; 3.0 SDK is now live on MSDN!
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p style="font-size: 10pt; font-family: Arial"&gt;I am happy to announce that the online version of the Microsoft CRM 3.0 SDK is now live on MSDN: &lt;a href="http://msdn.microsoft.com/library/en-us/CrmSdk3_0/htm/v3d0microsoftcrmv3d0sdk.asp"&gt;http://msdn.microsoft.com/library/en-us/CrmSdk3_0/htm/v3d0microsoftcrmv3d0sdk.asp&lt;/a&gt;&lt;/p&gt;
&lt;p style="font-size: 10pt; font-family: Arial"&gt;The online version will be updated quarterly, beginning in January. &lt;/p&gt;
&lt;p style="font-size: 10pt; font-family: Arial"&gt;You can find the download version, along with other downloads, here: &lt;a href="http://msdn.microsoft.com/MBS/Downloads/CRMdownloads/default.aspx"&gt;http://msdn.microsoft.com/MBS/Downloads/CRMdownloads/default.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p style="font-size: 10pt; font-family: Arial"&gt;3.0 database diagrams will be available on the download page within the next few weeks.&lt;/p&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=504755" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mikemill/archive/tags/Microsoft+CRM/default.aspx">Microsoft CRM</category></item></channel></rss>