Thursday, February 16, 2006

Integrating Team-Sites into MSCRM

We usually implement SharePoint (both WSS and SPS) at our MSCRM customers to provide collaboration and document archive functionality. We use the iframe-style presentation layer integration mechanism that MSCRM provides through the ISV.CONFIG.XML file (ISV.CONFIG in v1.2). Microsoft has even provided an XSD schema for this configuration file in v3.0. You will find these files in the \_Resources\ folder underneath the install directory of MSCRM.

I will explain what you need to do to integrate WSS team-sites into MSCRM, and which modifications you should make to the web-part pages (WPP) and document libraries (doc-libs) of a team-site to make them well-behaved parts of MSCRM.

Our MSCRM-WSS integration is based on using some intermediate "staging" .ASPX pages that are the targets for e.g. the MSCRM <NavBarItem> element's URL attribute. We typically used two pages, one for doc-libs and one for other collaboration features of SharePoint:

<!-- The Account Left Nav Bar -->
<NavBar ValidForCreate="0" ValidForUpdate="1">
<NavBarItem Icon="/_imgs/ico_18_1.gif" Title="Document Archive" Url="http://london/Objectware.Mscrm.SharePoint/TeamSiteSharedDocuments.aspx" Id="Account.SharedDocs"/>
<NavBarItem Icon="/_imgs/ico_18_9.gif" Title="Collaboration" Url="http://london/Objectware.Mscrm.SharePoint/TeamSiteSummary.aspx" Id="Account.ViewTeamSite"/>
<NavBarItem Icon="/_imgs/ico_18_9.gif" Title="Links" Url="http://london/Objectware.Mscrm.SharePoint/TeamSiteSummary.aspx" Id="Account.ViewLinks"/>

Note that the PassParams attribute of v1.2 is now obsolete, and that the object type and guid now always get passed to the target page. Note the Id attribute; it is central in making the integration flexible. Use the attribute to pass different "tokens" to the staging-page to allow the page to provide different parts of the SharePoint team-site as the response. The parameters are passed as a querystring. Get the passed data in the Page_Load event of your .ASPX page:

string guid = Request.QueryString["oId"];
string type = Request.QueryString["oType"];
string tabSet = Request.QueryString["tabSet"];

Note that
the Id attribute has the key tabSet in the URL querystring. Note also that the tabSet value gets the suffix "area", e.g. Account.ViewLinks becomes Account.ViewLinksarea. The oId value is the entity record GUID and the oType value is the type of the entity. Some of the most used types are:
  • Account = 1
  • Contact = 2
  • Opportunity = 3
  • Incident (case) = 112
Now that you know exactly which entity that requested your staging-page to show which specific WPP of a team-site, all you need to determine is which team-site it is, whether it exists, and whether the requesting user has access to the page (i.e. is a team-site member). Deducing the team-site URL from the parameters is left as an exercise for you, but a simple approach is to use the entity GUID a the only varying part of the team site URL, for example:

We also use a team-site generator made by Mads Nissen to allow a user to create new team-sites directly from inside MSCRM should the team-site not exists. The method shown below is used to check whether a team-site exists or not for e.g. a specific account. Lately, we have started using workflow to get more flexibility and power in the team-site creation process.

Your staging-page should use <identity impersonate="true"> in the relevant WEB.CONFIG file to ensure that you assert team-site access as the logged on MSCRM user. You could use the SharePoint object model to check if the site exists and if the user is a member. I have chosen the simpler method of using the HttpWebRequest of the System.Net namespace and checking for exceptions, making some simple assumptions:

public static void CheckTeamSiteUrl(string url)
string response = "";
HttpWebResponse httpResponse = null;

//assert: user have access to URL
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
httpResponse = (HttpWebResponse)httpRequest.GetResponse();
catch(Exception ex)
throw new ApplicationException("HTTP 403 Access denied, URL: " + url, ex);

//if here, the URL is correct and the user has access
StreamReader stream = new StreamReader(httpResponse.GetResponseStream());
response = stream.ReadLine(); // .ReadToEnd();
catch(Exception ex)
throw new ApplicationException("HTTP 404 Page not found, URL: " + url, ex);

if(response.ToLower() == "<html><body>the web site that is referenced here is not in the configuration database.</body></html>")
throw new ApplicationException("HTTP 404 Team-site not found, URL: " + url, null);

Note that WSS won't respond with a proper HTTP 404 error when the team-site does not exist. Rather, WSS responds with a valid page with a single line of text explaining that there is no such team-site in the SharePoint database.

If the CheckTeamSiteUrl method returns failure, a new team-site is generated from a WSS template (.STP) using the standard SharePoint web-services. The WSS template contains one or more web-part-pages (WPP) tailored for integration into MSCRM (see below).

If the
CheckTeamSiteUrl method returns success, do a simple redirect to the actual target page within the WSS team-site.

You should tailor the WPPs that you integrate into MSCRM for these reasons:
  • To remove the SharePoint "chrome": i.e. the page header, top menu, search, left menu, etc
  • To configure the custom MSCRM view(s) of the doc-lib to use only basic column types rather than the "edit" column types, to keep the navigation options simple and controllable
  • To configure doc-lib toolbars to be suitable for inline navigation in MSCRM
  • To ensure that all hyperlinks are suitable for navigation within the MSCRM frame: if a link is not suitable for inline navigation, apply a target="_blank" attribute to it
How you create a new WPP depends on wether it is a new custom team-site page or a new custom view for an existing document library. To create a new team-site page, open the WPP you want to integrate into MSCRM in FrontPage2003 and save it as a new web-page for use in MSCRM. To create a custom view for a doc-lib, I recommend using the standard 'Modify settings and columns-Views-Create a new view' tool. Tailor the new view to be suitable for inline navigation in MSCRM. It is better to do all customizations before hiding the SharePoint "chrome", as hiding the chrome also hides access to the customization tools.

I prefer to use the prefix MsCrmView_ on all web-part-pages tailored for integration into MSCRM. Use the 'split' view of the WPP to select the parts to remove, and apply a style="display: none;" attribute to the <TR> and <TD> elements to hide them. Do not delete them from the page, some SharePoint JavaScript might depend on the elements being part of the HTML DOM.

As a web-part-part page is built at run-time from the web-parts residing in the web-part-zones of the page, you need to device a JavaScript that runs on page load 'complete' event to modify their navigation behavior (the target attribute). This script
is left as an exercise for you.
[UPDATE] The hyperlink modification JavaScript can be found here, including further details.

Do not hesitate to remove the SharePoint "Modify shared page" menu link. The toolbox can always be summoned using this querystring:
?mode=edit&PageView=Shared&toolpaneview=2 (see SharePoint tweaks).

Also try this nifty little SharePoint querystring trick: ?contents=1


Anonymous said...

Thanks for the tip. Do you have any code that ypu can provide for this solution?

Kjell-Sverre Jerijærvi said...

Actually, there is very little code involved, except for the team-site generator. Most of the work for setting up this solution building the WSS team-site template (.STP file) using FrontPage2003.

We have recently switched to using the K2 workflow engine as it gives ut much more power and flexibility in generating team-sites (e.g. adding members, team-site hierarchy, initial content, etc).

If you still want to code your own team-site generator, use the SPWeb.Add metod to create the site. As you will need some more logic, I recommend creating a custom SharePoint web-service to contain your team-site generator.

Objectware currently has no plans for publishing the team-site generator code.

Kjell-Sverre Jerijærvi said...

More detailed description of customizing the team-site with FP2003 at the MSCRM team blog:

Anonymous said...

Hi there,

iS it possible to view Sharepoint web services on the CRM Outlook Client with no hassles?

Kjell-Sverre Jerijærvi said...

No it isn't, the SharePoint sites are not available off-line. You can mark the team-site views as not available for the laptop client.