Do you want to customize help in CRM 2011?

I’ve run into a number of customers/partners who want to customize or replace the out of the box help in CRM 2011.  The guidance in the SDK is to host your custom help documentation in your own web site and surface in the CRM UI from the Get Started pane:

http://bit.ly/zIbLO6

However, for some, this is not enough.  Usually, the scenario is something like:

“We’ve done heavy xRM customization such that the built in help is out of context and confusing for our users.  We want to either modify, remove, or replace the built in help to eliminate the confusion to our users.”

After asking around internally about this, I was pointed to the following Connect feature request entry:

http://dkdt.me/A3fuMt

So if you feel strongly about the need for this capability, make sure you vote!

NOTE: If you are having issues with the voting link, then you might have to do the following first:

@devkeydet

Dynamics CRM 2011 Developer Tips and Tricks

Yesterday, I delivered a presentation with this title to the CRMUG US Public Sector SIG.  This deck is basically a set of things that I either wondered myself or have been asked by customers since shifting my focus from pure app dev to building solutions on Dynamics CRM as a development platform.  The deck links back to a number of my posts here as well as having some “coming soon” place holders that will become blog posts / how do I videos once I find the time.  Even though I don’t have published examples of all the things I mention in the deck, I have done sufficient “proof of concepts” that will be the basis for future posts.  The point being that I’ve gotten all this stuff working, I just need to clean it up and package it up as a post/sample/video.  I’ll be evolving this deck over time, including updates and additions.  When I do, I will update this post with the “what’s new” details.

direct link: http://dkdt.me/JUkQrl

@devkeydet

Cross domain calls to the parent CRM 2011 form

UPDATE: Added reference to another blog post that does a great job of going into the cross-document / cross-domain issue.  Fixed some grammar/typos.

UPDATE2: You might also be interested in my newer post: Cross domain calls from JavaScript

I’ve spoken to some folks recently who built solutions using CRM 4.0 and were fond of the ability to put custom ASP.NET (aspx) pages in the ISV folder.  As of CRM 2011, this is a deprecated feature. This has caused a bit of heartache and frustration with those fond of the feature.  The CRM 2011 SDK provides guidance on how to address this in the following sections:

Upgrade Code in the ISV folder to Microsoft Dynamics CRM 2011

Implement Single Sign-on from an ASPX Webpage or IFRAME

Walkthrough: Single Sign-on from a Custom Web Page

What you’ll find in the guidance is a new approach that works similarly to the ISV folder approach.  The major difference is that your custom ASP.NET pages run in a separate web site, hence a separate IIS Application Pool.  The forced decoupling of your code executing in the same context as the CRM Server code is a good thing in my opinion.  This is very similar to how plugins run in isolation.  By allowing your ASP.NET code to run in-process with the CRM Server code, the 4.0 approach was at the mercy of poorly written code.  Your code could actually adversely effect the CRM UI.  As I understand it, this happened quite a bit in the 4.0 days.  Isolation of your code from CRM code is more resilient.  Although probably less often used, an added benefit of this separation of is that you have another boundary that can be scaled independently.  Depending on the nature of your code, there may be value in running your stuff on their own servers. 

The downside of this forced decoupling is that it does add some complexity.  You can’t just drop ASP.NET code in a folder and have everything “just work.”  Setting this configuration up in an on-prem environment using windows authentication without SSL is relatively painless with no apparent side effects.  However, CRM 2011 has quite a bit of flexibility in how it can be configured.  In some of the more advanced configurations, an issue with a commonly used approach in CRM 2011 JavaScript programming will surface.  More and more people will run into this as they move to claims based authentication.  This post is my attempt to help shed some light on the situation and provide an alternative approach.

It is quite common for people to use window.parent from a child page in the companion web site (hosted within an IFrame) to call a JavaScript function written in a web resources hosted in the parent CRM form.  Here’s an example:

window.parent.someFunction(someData);

…where the parent form has a JavaScript web resource that looks like this:

function someFunction(someData)

{

    // Do something with someData

}

The issue surfaces when your companion site is running in a different domain (or even subdomain).  Browsers will surface a security error and prevent the call from happening.  Why would you run the companion site in a different domain/subdomain?  Here are a few reasons:

  • You use CRM Online and the companion site is in Windows Azure, Office 365, or any hosting provider for that matter
  • You are using claims based authentication with an internet facing deployment (IFD) 
  • If you are using SSL for your CRM deployment, then you must use SSL for your companion site which means you can’t differentiate the sites by port because they both require 443.  BTW, you can use wildcard certificates and host headers to bind to 443 multiple times on the same server.

So what’s the issue?  Well you can’t call window.parent unless both pages share the same domain of origin.  Now if you are web savvy, you might say “aha, but I can use document.domain on both ends!”  And you would be justified in assuming you could.  However there are some issues:

  • document.domain only works for sites that are subdomains of the primary domain (ex: a.domain.com and b.domain.com)
  • document.domain won’t work for child pages hosted in Windows Azure, SharePoint Online, or anywhere else that’s not in the domain of your CRM deployment
  • Most importantly, using document.domain has an adverse side effect that causes CRM 2011 functionality to fail in certain scenarios

It’s important to understand that the cross domain issue has nothing to do with CRM 2011.  It has everything to do with how browsers work.  As a security measure, they don’t allow you to make cross domain calls.  One could argue that you didn’t have to deal with this when the ISV folder was an option.  Fair enough, but I’ve already made my case for why the deprecation of the ISV folder was a good thing.  If you choose to ignore the fact that the ISV folder has been deprecated, you put yourself or your customer in jeopardy for upgradeability in the future.  Don’t to it.  Period.

Ok, enough background…how do you make this work if you absolutely must have window.parent.someFunction like interaction from a child page in another domain and a CRM form?  There’s an API in modern browsers called window.postMessage.  Not all browsers support window.postMessage.  However, there’s a handy little library that wraps window.postMessage and includes a fallback mechanism for legacy browsers:

http://benalman.com/projects/jquery-postmessage-plugin/

In my tests, I’ve been able to successfully use this approach across a number of scenarios.  I’ve created a sample of the approach in action.  Here are the instructions to get it working:

If I’ve explained that right, you should have the sample working.  The instructions are purposefully vague so they can be applied to the various scenarios this can run in. 

NOTE: I only pass a string message in the sample.  To pass a more rich data structure, I’d recommend using the wildly popular json2.js file to stringify/parse JavaScript Object Notation (JSON) on each end.

There’s another helper library called easyXDM that’s similar to the jQuery postMessage plugin I use in the sample.  They both use the same basic approach.  I chose jQuery postMessage because it was lighter weight and got the job done.  easyXDM is more feature rich and worth looking at as well.  There’s a great article here that talks about this whole scenario in even more detail, outside of the CRM context.  It also mentions easyXDM at the end.

What’s the lesson here?  Don’t use window.parent.  Instead, use window.postMessage or the helper library I use in my samples.  By doing this, you have a solution that will work in all the major combinations of possible CRM 2011 deployment environments:

  • on-prem with windows authentication
  • on-prem with claims based authentication
  • IFD with claims based authentication
  • CRM Online with Office 365
  • CRM Online with Windows Azure
  • Pretty much anything that has SSO configured

@devkeydet

Displaying a lookup as a dropdown in a CRM 2011 form

UPDATE (04JUN2013):  If you need to evolve this sample to support a one to many relationship represented as a multi-select, I like this multi-select control which can be themed with jQuery UI themes.

Another scenario from a customer:

We want to use a lookup to another entity because we want to store additional data in the  entities fields and option sets don’t provide this capability.  However, we want the selection of the entity in the form to be a dropdown to minimize the # of clicks a user must go through to select the entity.

HTML / JavaScript web resources and the OData service to the rescue!  First, this sample was loosely inspired by this post from my teammate Carlton Colter.  I took his idea, ran with it, applied it to this problem, and made my solution a reusable web resource that you can pass parameters to in order to apply it to any lookup on a form.  Here are the steps…

Add the lookup field to the form:

image

Notice that this lookup is required.  This solution respects the required metadata of the field and uses it to ensure the dropdown has a value before the form is saved.  Set the properties of the lookup making sure the Visible by default option is unchecked:

image

Insert an html web resource to the form with the following General settings configured (the code for the web resource is available further down):

image

The Custom Parameter(data) property is what makes this reusable.  You can figure out what needs to be passed in by looking at the JavaScript, but here is the comma separated format:

lookupEntitySetName,lookupEntityIdFieldName,lookupEntityDisplayFieldName,nameOfLookupFieldOnForm,webResourceName

Here is a longer description if the variable names aren’t clear enough:

lookupEntitySetName = Name of the entity set in the OData service for the entity.

lookupEntityIdFieldName = The id/primary key for the in the OData service.

lookupEntityDisplayFieldName = The field name from the entity that you want to display in the dropdown.

nameOfLookupFieldOnForm = The name of the actual lookup field that is hidden on the form.

webResourceName = The name of the web resource on the form.  This is set in the Add Web Resource dialog and always starts with WebResource_.

Make sure you set the properties on the Formatting tab like so:

image

Finally, there is a little bug that I gave up on.  So you will need to put a spacer next to or below the web resource:

image

This will prevent the dropdown for getting cut off if there is nothing to the right or bottom of it.  If it already has something to the right of it or below it, then this is unnecessary.  Bingo bango!  You now have a lookup that’s represented on the form as a dropdown complete with required validation:

image 

The dropdown is just UI trickery.  When you save the form, the value of the lookup is saved correctly.  In update scenarios, the form loads, reads the hidden lookup value, and sets the dropdown selected item appropriately.

Here’s the code for the html web resource:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

    <head>

        <title></title>

        <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>

        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js" type="text/javascript"/>

        <script src="scripts/dropdownforlookup.htm.js" type="text/javascript"/>

 

        <!-- TOOD: move the needed styles into our own stylesheet. The CRM team doesn't support referencing their styles because they can change -->

        <link href="/_common/styles/fonts.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/global.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/select.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

    </head>

    <body style="background-color: rgb(246, 248, 250); border-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-top: 0px;">

        <!-- TOOD: move the needed styles into our own stylesheet. The CRM team doesn't support referencing their style sheets because they can change -->

        <select id="lookupdropdown" class="ms-crm-SelectBox">

            <option value="Loading..." selected="selected">Loading...</option>

        </select>

    </body>

</html>

Here’s the code for the dropdown.htm.js file that it references:

$(document).ready(function () {

    var context = GetGlobalContext();

    var params = context.getQueryStringParameters();

    // The data passed to the web resource should be in the following format:

    //

    // lookupEntityName,lookupEntityIdFieldName,lookupEntityDisplayFieldName,nameOfLookupFieldOnForm,webResourceName

    //

    var dataParam = params.data.split(",");

    var lookupEntitySetName = dataParam[0];

    var lookupEntityIdFieldName = dataParam[1];

    var lookupEntityDisplayFieldName = dataParam[2];

    var nameOfLookupFieldOnForm = dataParam[3];

    var webResourceName = dataParam[4];

 

    var oDataQuery = context.getServerUrl() + "/XRMServices/2011/OrganizationData.svc" +

    "/" + lookupEntitySetName + "?$select=" + lookupEntityIdFieldName + "," + lookupEntityDisplayFieldName;

 

    var lookupAttribute = window.parent.Xrm.Page.getAttribute(nameOfLookupFieldOnForm);

    var lookupArray = lookupAttribute.getValue();

 

    $.getJSON(oDataQuery, function (data) {

        var results = data.d.results;

        var lookupdropdown = $("#lookupdropdown");

 

        for (var i = 0; i < results.length; i++) {

            var option = "<option value='" + results[i][lookupEntityIdFieldName];

            option += "'>" + results[i][lookupEntityDisplayFieldName] + "</option>";

            lookupdropdown.append(option);

        }

 

        lookupdropdown.prepend("<option value='blank'></option>");

 

        if (lookupArray) {

            var lookupId = lookupArray[0].id.replace("{", "").replace("}", "").toLowerCase();

            lookupdropdown.val(lookupId);

        } else {

            lookupdropdown.val("blank");

        }

 

        $("#lookupdropdown option[value='Loading...']").remove();

 

        lookupdropdown.width("100%"); // couldn't figure out what was causing it to not stretch so I just forced it

 

        lookupdropdown.change(function () {

            var name = $("#lookupdropdown option:selected").text();

            if (name == "") {

                SetLookupValueToNull(nameOfLookupFieldOnForm);

            } else {

                var entityType = results[0].__metadata.type.replace("Microsoft.Crm.Sdk.Data.Services.", "");

                SetLookupValue(nameOfLookupFieldOnForm, lookupdropdown.val(),

                name, entityType);

            }

        });

    });

 

    var requiredLevel = lookupAttribute.getRequiredLevel();

 

    if (requiredLevel == "required") {

        // We want to drive whether our dropdown requires a value by the hidden lookup fields metadata

        // However, if we keep the lookup field's requirement level to required the form validation

        // will tell us it is required an force us to show it.

        lookupAttribute.setRequiredLevel("none");

 

        //NOTE: Modifying html that the CRM server sends down to the browser is not supported.

        // However, here we are finding a label for this control and updating its text.

        // This is relatively harmless and the likelihood of the CRM representing a label

        // for a control as anything other than an html label control is low. So I feel safe

        // enough to break the "don't touch the CRM html" rule. Even if it becomes an issue

        // at upgrade, we have one place where we can make the adjustments

        var label = $("label[for='" + webResourceName + "']", window.parent.document);

 

        // TODO: Improve this so it isn't tightly coupled to CRM generated html/css. Using undocumented css and server urls is unsupported.

        label.append("<IMG class=ms-crm-ImageStrip-frm_required alt=Required src='/_imgs/imagestrips/transparent_spacer.gif?ver=600790655'>");

 

        // TODO: add onsave to display an error message.

        window.parent.Xrm.Page.data.entity.addOnSave(function (context) {

            var name = $("#lookupdropdown option:selected").text();

            if (name == "") {

                var labelForWebResource = window.parent.Xrm.Page.getControl(webResourceName).getLabel();

                alert("You must provide a value for " + labelForWebResource + ".");

                context.getEventArgs().preventDefault();

            }

        });

    }

});

 

function SetLookupValue(fieldName, id, name, entityType) {

    if (fieldName != null) {

        var lookupValue = new Array();

        lookupValue[0] = new Object();

        lookupValue[0].id = id;

        lookupValue[0].name = name;

        lookupValue[0].entityType = entityType;

 

        window.parent.Xrm.Page.getAttribute(fieldName).setValue(lookupValue);

    }

}

 

function SetLookupValueToNull(fieldName) {

    if (fieldName != null) {

        window.parent.Xrm.Page.getAttribute(fieldName).setValue(null);

    }

}

@devkeydet

Showing a jQuery UI dialog in a CRM 2011 form

I was asked how to implement the following scenario in a CRM 2011 form (paraphrased):

  • Show an alert notification indicator in the header
  • When the user to click the notification indicator, show a dialog with the details of the alert

Here’s how I did it.  The code below assumes you’ve already wired up jQuery and jQuery UI to the form.

Add an html web resource to the header:

image

Configure the web resource properties:

imageimage

Here’s the markup for the html web resource:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

    <head>

        <title></title>

        <script src="../ClientGlobalContext.js.aspx" type="text/javascript"/>

        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js" type="text/javascript"/>

        <script src="scripts/dialogfromheader.htm.js" type="text/javascript"/>

        

        <!-- TODO: move the needed styles into our own stylesheet.  The CRM team doesn't support referencing their styles because they can change -->

        <link href="/_common/styles/fonts.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/global.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

        <link href="/_common/styles/select.css.aspx?lcid=1033" rel="stylesheet" type="text/css"/>  

    </head>

    <!-- TODO: move the style info into our own stylesheet. -->

    <body style="background-color: rgb(246, 248, 250); border-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-top: 0px;">

        <img id="alert" src="images/alert_icon_red.jpg" alt="alert icon"

             width="25px" height="25px" style="cursor:pointer"/>

    </body>

</html>

Here’s the code for the referenced dialogfromheader.htm.js script file:

$(document).ready(function () {

    // Execute an OData ajax query to determine if there are alert records (stored in a related entity)

    // You probably need to pass entity id to the page from the CRM form to compose a proper query

    // If alerts exist show the alert UI, otherwise do nothing

    // I am not doing that here, but it should be obvious enough

 

    // If you have results, build up the html to put in the dialog to represent the alerts information

    var htmlForTheDialog = "<p>PLACED HOLDER FOR THE ALERT HTML</p>";

 

    $("#alert").click(function() {

        window.parent.dkdt_showDialog(htmlForTheDialog);

    });

});

Add a JavaScript web resource to the form:

image

Here’s the code for the referenced dialogsetup.js script file:

function dkdt_wireupDialog() {

    // NOTE: This clearly deviates from the 

    // "don't touch the HTML generated by the CRM UI" guidance from the SDK

    // Typically, I urge people not to do this because it is technically unsupported.

    // However, in this case we're not really modifying the generated UI.

    // We are just adding a div to the body of the html.

    // I'm accepting that I am doing something that's unsupported, but still relatively low risk of side effects

    $("body").append("
"
);

    $("#dkdt_dialog").dialog({ autoOpen: false, position: "top" });

}

 

function dkdt_showDialog(dialogHtml) {

    $("#dkdt_dialog").html(dialogHtml);

    $("#dkdt_dialog").dialog("open");

}

Now, when an end user clicks on the alert icon they will see the alert details:

image

@devkeydet

Referencing JavaScript files from a CDN in a CRM 2011 form

UPDATE: I’ve changed the approach in this post because the original code has some side effects where it doesn’t always load correctly, plus I discovered RequireJS.

I’m a big fan of referencing JavaScript files from a Content Delivery Network (CDN) when it makes sense.  Why?  I think the Microsoft Ajax CDN site does a good job of explaining things:

http://www.asp.net/ajaxlibrary/cdn.ashx

“The Microsoft Ajax Content Delivery Network (CDN) hosts popular third party JavaScript libraries such as jQuery and enables you to easily add them to your Web applications. For example, you can start using jQuery which is hosted on this CDN simply by adding a <script> tag to your page that points to ajax.aspnetcdn.com.

By taking advantage of the CDN, you can significantly improve

the performance of your Ajax applications. The contents of the CDN are cached on servers located around the world. In addition, the CDN enables browsers to reuse cached third party JavaScript files for web sites that are located in different domains.”

It may not be obvious at first, but you can do this within your CRM 2011 solutions as well.  CAVEAT: This might fall into the “don’t muck with our DOM” mantra of CRM development…I can’t guarantee this is an officially supported scenario.  But as they say, it works and the risk is pretty low.

Please read my Using RequireJS with CRM 2011 forms post.  Once you have the following web resource code should make sense:

function dkdt_referencejQueryFromCDN() {    

    // Check to see if jQuery is already loaded

    // If not, then load it

    if (typeof jQuery == 'undefined') {

        // NOTE: use https if your CRM deployment is running under https

        require(["http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js", function (m) {

            // Do what you would normally do after the file was loaded

        });                

    }

}

Add require.js followed by the web resource that contains the code above to the form.  Wire up the Form OnLoad to call the function in your web resource:

image

BAM!  You have a just referenced a CDN based JavaScript file.  You now have all the benefits that a CDN reference offers.

@devkeydet

Adding an Image Carousel to a CRM 2011 Form

I recently had a customer request to display the pictures/images attached to a CRM form in an image carousel.  This is one of those things where I’ve seen people write a bunch of Silverlight code to accomplish.  In my opinion, using Silverlight for this is overkill.  Inspired by the second half of the Displaying a Contact’s Facebook Picture in Microsoft Dynamics CRM 2011 post, I modified the OData query slightly to get back all the images attached to an entity and then used jCarousel Lite in conjunction with an HTML web resource. 

ImageCarousel.htm:

<html>

<head>

    <title></title>

</head>

<body style="background-color: rgb(246, 248, 250); border-width: 0px; margin-bottom: 0px;

    margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-top: 0px;">

    <table>

        <tr>

            <td>

                <button id="prev"><<</button>

            </td>

            <td>

                <div id="carousel">

                    <ul id="carousel-ul">

                    </ul>

                </div>

            </td>

            <td>

                <button id="next">>></button>

            </td>

        </tr>

    </table>

</body>

<script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>
   1:  

   2: http://span

   2: http://span

   2: <script src="scripts/ImageCarousel.htm.js" type="text/javascript">

</script>

</html>

ImageCarousel.htm.js:

$(document).ready(function () {    

    var context = GetGlobalContext();     

    

    // Get the entity id    

    var entityId = context.getQueryStringParameters().id;     

 

    if (entityId) {        

    

        // Build the OData query to get all the images attached to the current entity        

        var oDataQuery = context.getServerUrl() + "/XRMServices/2011/OrganizationData.svc" +            

        "/AnnotationSet?$select=AnnotationId,Subject,DocumentBody,MimeType&" +            

        "$orderby=ModifiedOn desc&$filter=ObjectId/Id eq guid'" + entityId +            

        "' and IsDocument eq true and startswith(MimeType,'image/') ";

        

        // Get a reference to the carousel ul        

        var carouselul = $("#carousel-ul");         

 

        // Execute the OData query for the images        

        $.getJSON(oDataQuery, function (data) {            

            var results = data.d.results;                        

            

            // Add the results to the carousel ul            

            for (var i = 0; i < results.length; i++) {                

                // Build up an img tag surrounded by a li tag to add to the carousel ul                

                var img = "<li><img src='";                                

 

                // set src attribute of default profile picture web resource.                                    

                // here we use DataURI schema which has 32kb limit in IE8 and doesn't support IE <= 7.                                    

                var src = "data:" + results[i].MimeType + ";base64," + results[i].DocumentBody;                                

 

                img += src;                

                img += "' width='100' height='100' style='border: 1px solid; margin: 1px;' alt='";

                img += results[i].Subject + "'></li>";                                

 

                // Add the li with imag inside to the carousel ul                

                carouselul.append(img);

            }

 

            // Wire-up jCarouselLite to the carousel div            

            $("#carousel").jCarouselLite({

                btnNext: "#next",

                btnPrev: "#prev"

            });

        });

    } else {

        alert("could not get entity id");    

}});

The end result is what you see below:

Capture

We can rotate through all the images attached to this Contact entity by clicking the previous / next buttons.  This code will work with any entity that has Notes enabled.

@devkeydet

RELEASE: devkeydetValidation for CRM 2011 (1.1.70.0)

I’ve gone through and fixed the major bugs filed for My CRM 2011 Validation Framework.  I still have improvements to make, but wanted to focus on the bugs that were preventing people from using the framework “as-is” without tweaking the code themselves.  You can grab the latest source code from http://bit.ly/dkdtcrmval.  You can install the newest managed solution on top of the previous install.  In the managed upgrade scenario, there is a know issue where you will have 3 old web resources that are no longer used.  Cleaning that stuff up in a future release is on the TODO list.

@devkeydet

CRM 2011 Client Side VsDoc

Short post, but wanted it on my blog for reference.  Patrick Verbeeten has a very useful vsdoc file for CRM developers to get intellisense for Xrm.Page and GetGlobalContext when writing javascript code.  I asked him to put it on NuGet so it was easier to find/reference in Visual Studio.  He didSmile!

https://nuget.org/packages/Crm2011JsVsDoc

@devkeydet

Merging CRM 2011 Solutions

In the Organize Your Team To Develop Solutions section of the Microsoft Dynamics CRM 2011 SDK, there is a section that talks about merging 2 or more unmanaged solutions by importing them into a master solution.  However, the SDK doesn’t exactly explain how.  In this screencast, I will show you.

http://bit.ly/wnMl9u

https://channel9.msdn.com/posts/Merging-CRM-2011-Solutions/player?w=512&h=288

@devkeydet