3. Content Searching with Microsoft Office SharePoint Server
The search feature in Microsoft Dynamics CRM
provides only basic string matching against certain attributes, and
cannot search document context, unless the content resides in CRM, such
as CRM knowledge base articles. Using the built-in index and query
services in Microsoft Office SharePoint Server Enterprise edition can
empower users for a better search mechanism.
There are two possible ways to leverage SharePoint to enhance the search feature:
Indexing the CRM Data Using BDC
To configure this, you have to first identify
the entities and attributes you want to search using Microsoft Office
SharePoint Server. After you have identified all the entities, you must
establish the connection between SharePoint and Microsoft CRM using the
BDC (as explained in the previous section).
After the BDC connections have been set up to
retrieve data, it is recommended to configure a Search Center
specifically for the CRM data. This uses a single connection to retrieve
the data and display in SharePoint lists, for the search indexing
engine and the KPIs.
Search Center is used to enter query requests.
By default, the Search Center includes the following pages, located at
/SearchCenter/Lists/SearchCenter/AllItems.aspx (as shown in Figure 7):
Default.aspx: Default home for the Search Center
Advanced.aspx: Customizable for adding custom properties to filter the search results
People.aspx: To search for people in the SharePoint profile database
The
Search Results list displays the results from the query requested in
the Search Center pages. By default, this list includes the following
pages, located at /SearchCenter/Lists/SearchResults/AllItems.aspx:
Results.aspx: Default page with best bets, keywords, and the actual results page
Peopleresults.aspx: Results page for the people
Customize Search Center
Using the Search Center in a Microsoft
SharePoint System is a fast way to get to the customer records
efficiently. An example is an organization that uses SAP, Microsoft
Dynamics CRM, BusinessObjects, and a home-grown software application.
For end users to search everything about a customer, they will be
required to go to all those locations to get the full history about the
customer. The Search Center can provide a single interface to search
across several systems, to increase end-user productivity (see Figure 8).
In this example, we create a page in the Search
Center and the Search Results to filter the results to the data returned
from the BDC connection to Microsoft Dynamics (in the current example,
refining the results to the CRM accounts). This can be enhanced to
include other data sources, too, if desired.
Create the SharePoint search page and tab, as shown in Figure 9:
1. | Open the SharePoint List for the SearchCenter Tab control located at /SearchCenter/SearchCenter/AllItems.aspx.
|
2. | Click the New link.
|
3. | In the Tab Name field, enter Microsoft Dynamics CRM.
|
4. | In the Page field, enter MSCRM.aspx.
|
5. | Click OK.
|
Implement and customize the tabs on the search page as follows:
1. | Open the Microsoft Dynamics CRM search page.
|
2. | Click the Add a WebPart link in the top zone.
|
3. | Select Search Box, and then click Add.
|
4. | Select the drop-down arrow in the Search Box web part.
|
5. | Select Modify Shared WebPart.
|
6. | Expand the Scope Dropdown section in the tool pane.
|
7. | In the Dropdown Mode list, select Do Not Show Scopes.
|
8. | Expand the Miscellaneous section.
|
9. | Select the Target Search Results Page URL Override field.
|
10. | Click the ellipsis (...) button to open the Text Entry window for this field.
|
11. | Replace the URL Results.aspx with MSCRMResults.aspx.
|
12. | Click OK to save your changes.
|
After the Search Center has been created, we need to create the search results page:
1. | Open the SharePoint List for the SearchResults tab control located at /SearchCenter/SearchResults/AllItems.aspx.
|
2. | Click the New link.
|
3. | In the Tab Name field, enter Microsoft Dynamics CRM Results.
|
4. | In the Page field, enter MSCRMResults.aspx.
|
5. | Click OK.
|
Now implement and customize the tabs on the search results page:
1. | Open the Microsoft Dynamics CRM Results page.
|
2. | Click the Add a WebPart link in the top zone.
|
3. | Select Search Box, and then click Add.
|
4. | Select the drop-down arrow in the Search Box web part.
|
5. | Select Modify Shared WebPart.
|
6. | Expand the Scope Dropdown section in the tool pane.
|
7. | In the Dropdown Mode list, select Do Not Show Scopes.
|
8. | Expand the Miscellaneous section.
|
9. | Select the Target Search Results Page URL Override field.
|
10. | Click the ellipsis (...) button to open the Text Entry window for this field.
|
11. | Replace the URL Results.aspx with MSCRMResults.aspx.
|
12. | Click OK to save your changes.
|
13. | Click the Add a WebPart link in the middle left zone.
|
14. | Select Search Core Results.
|
15. | Click Add.
|
16. | Select the drop-down arrow in the Search Core Results web part.
|
17. | Select Modify Shared WebPart.
|
18. | Expand the Results Query Options section in the tool pane.
|
19. | Select the Selected Columns field.
|
20. | Select the ellipsis (...) button to open the Text Entry window for this field.
|
21. | Replace the existing XML for the Selected Columns property with the following:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SelectColumns>
<Column Name="Rank"/>
<Column Name="AccountName"/>
<Column Name="AccountNumber"/>
<Column Name="AccountTerritory"/>
<Column Name="AccountAddress1Name"/>
<Column Name="AccountModifiedDate"/>
<Column Name="CollapsingStatus"/>
<Column Name="HitHighlightedSummary"/>
<Column Name="HitHighlightedProperties"/>
</SelectColumns>
</root>
|
22. | Click OK to return to the tool pane.
|
23. | Click Data Form WebPart to display the XSL Editor.
|
24. | Click the Source Editor button to open the Text Entry window for the web part’s XSL property.
|
25. | Replace the contents of the XSL property with the following XSLT code:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
<!-- white space in XSL -->
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> <xsl:param name="ResultsBy" />
<xsl:param name="ViewByUrl" />
<xsl:param name="ViewByValue" />
<xsl:param name="IsNoKeyword" />
<xsl:param name="IsFixedQuery" />
<xsl:param name="ShowActionLinks" />
<xsl:param name="MoreResultsText" />
<xsl:param name="MoreResultsLink" />
<xsl:param name="CollapsingStatusLink" />
<xsl:param name="CollapseDuplicatesText" />
<xsl:param name="AlertMeLink" />
<xsl:param name="AlertMeText" />
<xsl:param name="SrchRSSText" />
<xsl:param name="SrchRSSLink" />
<xsl:param name="DisplayDiscoveredDefinition" select="True" />
<!-- When there is a keyword to issue the search -->
<xsl:template name="dvt_1.noKeyword">
<span class="srch-description">
<xsl:choose>
<xsl:when test="$IsFixedQuery"> Please set the Fixed Query property for the WebPartWebpart. </xsl:when>
<xsl:otherwise> Enter one or more words to search for in the search box. </xsl:otherwise>
</xsl:choose>
</span>
</xsl:template>
<!-- When an empty result set is returned from search -->
<xsl:template name="dvt_1.empty">
<div class="srch-sort">
<xsl:if test="$AlertMeLink and $ShowActionLinks">
<img src="/_layouts/images/bell.gif" border="0" height="9"
width="9" />
<span class="srch-alertme" >
<a href ="{$AlertMeLink}" id="CSR_AM1" title="{$AlertMeText}">
<xsl:value-of select="$AlertMeText" />
</a>
</span>
</xsl:if>
<xsl:if test="string-length($SrchRSSLink) > 0 and $ShowActionLinks">
<xsl:if test="$AlertMeLink"> | </xsl:if>
<span class="ms-rssfeed">
<a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="CSR_SR">
<xsl:value-of select="$SrchRSSText"/>
</a>
</span>
</xsl:if>
</div>
<br/>
<br/>
<span class="srch-description" id="CSR_NO_RESULTS">
No results matching your search were found. <ol>
<li>Check your spelling. Are the words in your query spelled correctly?</li>
<li>Try using synonyms. Maybe what you're looking for uses slightly different words.</li>
<li>Make your search more general. Try more general terms in place of specific ones.</li>
<li>Try your search in a different scope. Different scopes can return different results.</li>
</ol>
</span>
</xsl:template>
<!-- Main body template. Sets the Results view (relevance or date) options. -
->
<xsl:template name="dvt_1.body">
<div class="srch-results">
<xsl:if test="$ShowActionLinks">
<div class="srch-sort">
<xsl:value-of select="$ResultsBy" />
<xsl:if test="$ViewByUrl">
| <a href ="{$ViewByUrl}" id="CSR_RV" title="{$ViewByValue}">
<xsl:value-of select="$ViewByValue" />
</a>
</xsl:if>
<xsl:if test="$AlertMeLink">
| <img src="/_layouts/images/bell.gif" border="0" height="9" width="9" /> <span class="srch-alertme" >
<a href ="{$AlertMeLink}" id="CSR_AM2" title="{$AlertMeText}">
<xsl:value-of select="$AlertMeText" />
</a>
</span>
</xsl:if>
<xsl:if test="string-length($SrchRSSLink) > 0">
| <span class="ms-rssfeed">
<a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="CSR_SR">
<xsl:value-of select="$SrchRSSText"/>
</a>
</span>
</xsl:if>
</div>
<br />
</xsl:if>
<xsl:apply-templates />
<br />
<br />
</div>
<xsl:call-template name="DisplayMoreResultsAnchor" />
</xsl:template>
<!-- This template is called for each result -->
<xsl:template match="Result">
<xsl:variable name="id" select="id"/>
<xsl:variable name="url" select="url"/>
<span class="srch-Title">
<xsl:value-of select="accountname"/>
<br/>
</span>
<div class="srch-Description">
<xsl:choose>
<xsl:when test="hithighlightedsummary[. != '']">
<xsl:call-template name="HitHighlighting">
<xsl:with-param name="hh" select="hithighlightedsummary" />
</xsl:call-template>
</xsl:when>
<xsl:when test="description[. != '']">
<xsl:value-of select="accountdescription"/>
</xsl:when>
</xsl:choose>
</div >
<span class="srch-URL">
<a href="{$url}" id="{concat('CSR_U_',$id)}" title="{$url}">
<xsl:choose>
<xsl:when test="hithighlightedhroperties/HHUrl[. != '']">
<xsl:call-template name="HitHighlighting">
<xsl:with-param name="hh" select="hithighlightedhroperties/HHUrl" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="url"/>
</xsl:otherwise>
</xsl:choose>
</a>
</span>
<p class="srch-Metadata">
<xsl:call-template name="DisplayString">
<xsl:with-param name="str" select="AccountTerritory" />
<xsl:with-param name="prop">Territory:</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="DisplayString">
<xsl:with-param name="str" select="AccountAddress1Name" />
<xsl:with-param name="prop">Address Name:</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="DisplayString">
<xsl:with-param name="str" select="accountnumber" />
<xsl:with-param name="prop">Account Number:</xsl:with-param>
</xsl:call-template>
</p>
</xsl:template>
<xsl:template name="HitHighlighting">
<xsl:param name="hh" />
<xsl:apply-templates select="$hh"/>
</xsl:template>
<xsl:template match="ddd"> … </xsl:template>
<xsl:template match="c0">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c1">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c2">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c3">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c4">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c5">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c6">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c7">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c8">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c9">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<!-- A generic template to display string with non zero (0) string length
(used for author and last-modified time) -->
<xsl:template name="DisplayString">
<xsl:param name="str" />
<xsl:param name="prop" />
<xsl:if test='string-length($str) > 0'>
|| <xsl:value-of select="$prop" />  <xsl:value-of select="$str"
/>
</xsl:if>
</xsl:template>
<!-- document collapsing link setup -->
<xsl:template name="DisplayCollapsingStatusLink">
<xsl:param name="status"/>
<xsl:param name="url"/>
<xsl:if test="$CollapsingStatusLink">
<xsl:choose>
<xsl:when test="$status=1">
<br/>
<xsl:variable name="CollapsingStatusHref" select="concat(substring-before($CollapsingStatusLink, '$$COLLAPSE_PARAM$$'), 'duplicates:"', $url,'"', substring-after($CollapsingStatusLink, '$$COLLAPSE_PARAM$$'))"/>
<span class="srch-dup">
[<a href="{$CollapsingStatusHref}">
<xsl:value-of select="$CollapseDuplicatesText"/>
</a>]
</span>
</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:template>
<!-- The "view more results" for fixed query -->
<xsl:template name="DisplayMoreResultsAnchor">
<xsl:if test="$MoreResultsLink">
<a href="{$MoreResultsLink}" id="CSR_MRL">
<xsl:value-of select="$MoreResultsText"/>
</a>
</xsl:if>
</xsl:template>
<xsl:template match="All_Results/DiscoveredDefinitions">
<xsl:variable name="FoundIn" select="DDFoundIn" />
<xsl:variable name="DDSearchTerm" select="DDSearchTerm" />
<xsl:if test="$DisplayDiscoveredDefinition = 'True' and string-
length($DDSearchTerm) > 0">
<script language="javascript">function ToggleDefinitionSelection() {
var selection = document.getElementById("definitionSelection"); if (selection.style.display == "none") { selection.style.display ="inline"; } else { selection.style.display ="none"; } } </script>
<div>
<a href="#" onclick="ToggleDefinitionSelection(); return false;">
What people are saying about <b>
<xsl:value-of select="$DDSearchTerm"/>
</b>
</a>
<div id="definitionSelection" style="display:none;">
<xsl:for-each select="DDefinitions/DDefinition">
<br/>
<br/>
<xsl:variable name="DDUrl" select="DDUrl" />
<xsl:value-of select="DDStart"/>
<b>
<xsl:value-of select="DDBold"/>
</b>
<xsl:value-of select="DDEnd"/>
<br/>
<xsl:value-of select="$FoundIn"/>
<a href="{$DDUrl}">
<xsl:value-of select="DDTitle"/>
</a>
</xsl:for-each>
</div>
</div>
</xsl:if>
</xsl:template>
<!-- XSLT transformation starts here -->
<xsl:template match="/">
<xsl:variable name="Rows" select="/All_Results/Result" />
<xsl:variable name="RowCount" select="count($Rows)" />
<xsl:variable name="IsEmpty" select="$RowCount = 0" />
<xsl:if test="$AlertMeLink">
<input type="hidden" name="P_Query" />
<input type="hidden" name="P_LastNotificationTime" />
</xsl:if>
<xsl:choose>
<xsl:when test="$IsNoKeyword = 'True'" >
<xsl:call-template name="dvt_1.noKeyword" />
</xsl:when>
<xsl:when test="$IsEmpty">
<xsl:call-template name="dvt_1.empty" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="dvt_1.body"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- End of Stylesheet -->
</xsl:stylesheet>
|
26. | Click OK to return to the tool pane.
|
27. | Click OK to save the changes to the web part.
|
4. CRM Accelerators Inside SharePoint
Microsoft has recently released several CRM
accelerators. Some of these accelerators can be used to extract and
display information in SharePoint.
The available accelerators are as follows: