MS SQL and Searching MCMS with SharePoint

Last week, we discussed building our own search controls and other topics related to searching MCMS with SharePoint. This week, we conclude our discussion. This article is excerpted from chapter five of the book Advanced Microsoft Content Management Server Development, written by Lim Mei Ying et al. (PACKT, 2005; ISBN: 1904811531).

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 5
October 26, 2006
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

The Advanced Search and Results Page

Once we have our search input control built, we need a page that will execute the search against the SPS Query Service Web Service and display the results. In addition, like all other search result pages, we need to add advanced searching options such as limiting our search to the Tropical Green plant catalog.

Before we can start building the results page, we need to add a web reference to the SPS Query Service Web Service:

  1. In Visual Studio .NET, right-click the TropicalGreen project and select Add Web Reference.
  2. Enter the URL of the web service that will retrieve the search results. The URL of the Query Service is http://[portal]/_vti_bin/search.asmx. For this example, we'll use the portal created in Appendix A, http://portal.tropicalgreen.net/ _vti_bin/search.asmx. Then click the Go button. You will likely be prompted for a user ID and password since this is part of the SharePoint portal virtual server, which isn't configured for anonymous access.
  3. Once the web service loads and the available methods are shown in the Add Web Reference Dialog, click the Add Reference button to add the web service to our project.

For simplicity, the search results page we will create will not be a CMS template, rather it will be a standard ASP.NET Web Form in the root of the Tropical Green project.

  1. Right-click the project and select Add | Add Web Form.
  2. Give the new page the name SearchResults.aspx.
  3. In Design view, drag and drop the Styles.css file from Solution Explorer onto the form to apply the stylesheet to the page.
  4. Change the page layout to FlowLayout.
  5. Drag the following user controls into the designer:
    •    \UserControls\TopMenu.ascx
    •    \UserControls\RightMenu.ascx

  1. Switch to HTML view and modify the body tag as follows:
    <body topmargin="0" leftmargin="0"> 
  2. Add the following HTML code to the page between the <form> tags, replacing the two controls we just added:
    <form id="Form1" method="post" runat="server">
    <table width="100%" border="0" cellspacing="0" cellpadding="0"> 
      <tr>
        <td width="100%" colspan="2" valign="top" bgcolor="#ffcc00"> 
          <img src="/tropicalgreen/images/Logo.gif">
        </td>
        <td vAlign="top" rowSpan="10">
        </td>
      </tr>
      <tr bgColor="#66cc33">
        <td colSpan="2">
          <uc1:TopMenu id="TopMenu1" runat="server">
          </uc1:TopMenu>
        </td>
      </tr>
      <tr>
        <td vAlign="top" style="PADDING-RIGHT:30px; PADDING-LEFT:30px;
           PADDING-BOTTOM:30px; PADDING-TOP:10px">
          <p>&nbsp;</p>
          <table cellspacing="0" cellpadding="10" border="1"  
                 bordercolor="#669900">
            <tr vAlign="top">
              <td>
                <b>Tropical Green Search:<b/>
              </td>
            </tr>
            <tr>
              <td vAlign="top"> 
                <b>Advanced Search</b>
                <p>
                <b>Search Results</b>
              </td>
            </tr>
          </table>
        </td>
        <td class="RightMenuBar" width="20%" valign="top" height="100%"
                         align="center" rowspan="2" bgcolor="#669900">
          <uc1:RightMenu id="RightMenu1" runat="server">
          </uc1:RightMenu>
        </td>
      </tr>
    </table>
    </form>

We now have the basic layout for our advanced search and search results page, which looks similar to the other templates in our site. Let's add some controls for our advanced search.

  1. In Design view, drag a TextBox from the Toolbox and place it under the Advanced Search text.
  2. In Design view, drag a Button from the Toolbox and place it to the right of the TextBox.
  3. The next thing we need to add is a DataGrid to contain the results of the search. In Design view, drag a DataGrid control from the Toolbox to just under the Add Search Results Here text. We'll worry about formatting this control later, for now we just need something to show us our data.
  4. Set the properties of the controls we just added according to the following table:

PropertyValue
TextBox

ID = txtAdvancedSearch

Button

ID = btnAdvancedSearch

Text = Go

 DataGrid

ID = dgrSearchResults 

Our advanced search page should now look like this:

Now it's time to start coding our search logic. First, we need to add an event handler for our advanced search button.

  1. In Design view, double-click the btnAdvancedSearch button to create a click event handler. Visual Studio .NET will add an event handler method to the code-behind file.
  2. Add the following code to the btnAdvancedSearch_Click() event handler: private void btnAdvancedSearch_Click(object sender, System.EventArgs e)
    {
      string keywords = this.txtAdvancedSearch.Text; 
      keywords = HttpUtility.UrlEncode(keywords);
      Response.Redirect(Request.ApplicationPath
                     
    + "/SearchResults.aspx?keywords="
                     
    + keywords);
    }

Next, we need to check the querystring in the Page_Load() event handler to see if any keywords were passed from our SearchInput.ascx control or the txtAdvancedSearch TextBox.

Add the following code to check if there are any keywords supplied and execute the search if so:

  private void Page_Load(object sender, System.EventArgs e)
  {
    if (Request.QueryString["keywords"] != null
    && Request.QueryString["keywords"] != String.Empty)
 
    {
      string keywords =  
Request.QueryString["keywords"];
      DataSet ds = ExecuteSearch(keywords);
      this.dgrSearchResults.Visible = true;
      this.dgrSearchResults.DataSource = ds;
      this.dgrSearchResults.DataBind();

      // autofill the keyword input box with the search keywords 
      this.txtAdvancedSearch.Text = keywords;
   }
   else
   {
    
this.dgrSearchResults.Visible = false;
   }
 }

Now we need to create the method that will execute the search against our SPS content index. This method will:

  1. Create an instance of the Query Service Web Service we just added to the project.
  2. Call a method that will build the MSQuery to submit to the Query Service.
  3. Execute the search.
  4. Bind the search results to a DataGrid.

Import the following namespaces in the SearchResults.aspx.cs file:

  using System.Security.Principal;
  using System.Runtime.InteropServices;
  using System.Net;
  using System.Text;
  using System.Text.RegularExpressions; 
  using Microsoft.ContentManagement.Publishing;

Add the following method to the SearchResults.aspx.cs file after the Page_Load() event handler. This method will ensure the current thread is running under the original security context regardless of any impersonations that may have been invoked previously:

  // Get reference to the RevertToSelf method
  [DllImport("ADVAPI32.DLL")]
  public static extern int RevertToSelf();

  /// <summary>
  /// Builds the appropriate MSQuery,
  /// submits the query to the SPS Query Service,
  /// and returns the results as a DataGrid.
  /// </summary>
  /// <param name="keywords">String of keywords to search for.</param>
  /// <returns>DataSet of search results.</returns>
  private DataSet ExecuteSearch(string keywords)
  {
   
// decode the list of keywords
    keywords = HttpUtility.UrlDecode(keywords);

    // create reference to the Query Service Web service
    net.tropicalgreen.portal.QueryService spsQueryService =
                             new net.tropicalgreen.portal.QueryService();

    // use the current application pool identity to login
    // to the SharePoint Query Service Web service
    WindowsIdentity CurrentUser = WindowsIdentity.GetCurrent();

    try
   
{
      // use the Application Pool account to do access the
      // SharePoint Search Services
      RevertToSelf();
      spsQueryService.Credentials = CredentialCache.DefaultCredentials;
   
}
    catch(System.Exception exception)
    {
     
throw new System.Exception(exception.Message);
    }
    finally
    {
     
// ensure that the original user is being impersonated again
      CurrentUser.Impersonate();
      CurrentUser = null;
    } 
   
// build MSQuery XML string to send to the Query Service
    // - change the content source to "CMSChannels" if you used SearchSetup.exe
    string msQuery = BuildMSQuery(keywords, "Tropical Green website");

    // execute the query and return the dataset
    return spsQueryService.QueryEx(msQuery);
  }

If you used the SearchSetup.exe program to create your content sources, you should use
the content source group "CMSChannels" instead of "Tropical Green website" in the
code above.

Our ExecuteSearch() method calls another method, called BuildMsQuery(), which constructs the MSQuery for sending to the QueryEx() web method. An MSQuery is composed of XML tags that provide instructions to the Query Service, such as the number of results to return in the request and a Microsoft SQL full-text (MSSQLFT) query. Building the MSSQLFT query and MSQuery is likely to be the most complicated task in implementing the SharePoint search. We'll break it into two tasks: building the actual MSSQLFT query and building the MSQuery XML string. We'll first build the full-text query that our MSQuery will use in the construction of the XML string we'll send to the Query Service.

Building the Microsoft SQL Full-Text Query

SPS's search process uses full-text indexes and queries for fast keyword lookups in order to provide timely responses to the end user. Full-text queries are very similar to regular T-SQL queries in Microsoft SQL Server, but you have additional functions, or predicates, that you can use to give your query more power. One of these predicates that is useful when searching SharePoint indexes is FREETEXT. FREETEXT takes a list of words separated by spaces, determines which words and phrases are significant, and uses that information to build an internal query to search the targeted data in an efficient manner.

First, you need to be aware of the various fields, or properties, available to you in your query. SharePoint provides a list with this information in the Site Settings administration page of your portal.

  1. Open a new instance of Internet Explorer and navigate to our portal: http://portal.tropicalgreen.net.
  2. Click on the Site Settings link in the upper right. 
  3.  Under the Search Settings and Indexed Content section, click on the Manage properties from crawled documents link.

For each document crawled, the Manage Properties of Crawled Content page lists all properties that SharePoint could potentially contain indexed data on. For our purposes, we're only going to look at the two fields below, as they contain information for our search results page:

  • DAV:href
  • DAV:getlastmodified

Notice that some of the fields listed under the urn:schemas.microsoft.com:htmlinfo:
metainfo
group are the same fields as we added to our template META tags using the
SearchMetaTagGenerator user control from the MCMS Connector.

The other things we'll need are the name of the search scope we created, the name of the content index, and our keywords. Once we have all that information, it makes most sense to construct the MSSQLFT query in its own method for readability. We'll call this method BuildMssqlftQuery() and pass it a string containing our search keywords and the search scope to query. Add the following method at the end of the SearchResults.aspx.cs page:

  /// <summary>
  /// Builds the Microsoft SQL FullText query based on the parms.
  /// </summary>
  /// <param name="keywords">Keywords submitted for search.</param>
  /// <param name="searchScope">SPS Search scope to filter.</param>
  /// <returns>String of the MSSQLFT query.</returns>
  private string BuildMSsqlftQuery(string keywords, string searchScope)
  {
   
StringBuilder mssqlftQuery = new StringBuilder();
    ArrayList whereClause = new ArrayList();

    #region FILTER: keywords
    // list of keywords to include
    if (keywords != null && keywords.Length >0)
    {
     
// add the keyword filter, use a calculated weighted field
      // just as SPS does
      whereClause.Add(string.Format(" {0} {1}",
       
"WITH (\"DAV:contentclass\":0,"
      + "\"urn:schemas.microsoft.com: fulltextqueryinfo:description\":0,"
      + "\ urn:schemas.microsoft.com: fulltextqueryinfo:sourcegroup\":0,"
      + "\"urn:schemas.microsoft.com: fulltextqueryinfo:cataloggroup\":0,"
      + "\"urn:schemas-microsoft-com:office:office#Keywords\":1.0,"
      + "\"urn:schemas-microsoft-com:office:office#Title\":0.9,"
      + "\"DAV:displayname\":0.9,"
      + "\"urn:schemas-microsoft-com:publishing:Category\":0.8,"
      + "\"urn:schemas-microsoft-com:office:office#Subject\":0.8,"
      + "\"urn:schemas-microsoft-com:office:office#Author\":0.7,"
      + "\"urn:schemas-microsoft-com:office:office#Description\":0.5,"
      + "\"urn:schemas-microsoft-com:sharepoint:portal:profile:"
      + "PreferredName\ ":0.2,contents:0.1,*:0.05) "
      + "AS #WeightedProps",
        "FREETEXT(#WeightedProps, '" +keywords.ToString().Trim() +"')")
        ); 
    }
    #endregion

    #region FILTER: sps source group
    // filter source group
    whereClause.Add(string.Format(" {0}",
      "(\"urn:schemas.microsoft.com: fulltextqueryinfo:Sourcegroup\" = '"
     
+ searchScope +"')"));
    #endregion

    //build search query
    mssqlftQuery.Append("SELECT ");
    mssqlftQuery.Append("\"DAV:href\",");
    mssqlftQuery.Append("\"DAV:getlastmodified\"");
    mssqlftQuery.Append(" FROM Non_Portal_Content..SCOPE()");

    mssqlftQuery.Append(" WHERE ");
   
int i=0;
   
foreach (string s in whereClause)
   
{
     
if (i > 0)
       
mssqlftQuery.Append(" AND ");
      mssqlftQuery.Append(s);
     
i++;
   
}
   
return mssqlftQuery.ToString();
  }

Notice we added a calculated field, which we used to apply certain weight to some fields. This is how SharePoint actually executes its own search. You could configure the property weighting to give more emphasis to specific properties in your query. For example, you may want to give more weight to the title of the page, or to the keywords stored in the HTML META tags, than to the contents of the page.

Now that we have this method, let's move on to creating the MSQuery string. We'll use this method in the construction of our MSQuery string.

Building the MSQuery XML String

We know that the SPS Query Service Web Service accepts a single parameter: an MSQuery string. This string is actually an XML document, but it's passed to the Query Service as a string. The XML tags in this string tell the Query Service the type of response it supports, how many records to return in the result, and the result index to start the search results at. The <StartAt></StartAt> element is what you can use in paging your result set. We won't be incorporating paging into our site as it is small, but you can see how easy it would be to do so.

Let's get started, by creating our BuildMsQuery() method that returns a complete MSQuery XML string containing all the information necessary to execute a query against a SharePoint index. Add the following method at the end of the SearchResults.aspx.cs page:

  /// <summary>
  /// Builds an MSQuery with an embedded MSSQLFT query embedded
  /// for submission to SharePointPS Query Service.
  /// </summary>
  /// <param name="keywords">Keywords submitted for search.</param>
  /// <param name="searchScope">SPS Search scope to filter.</param>
  /// <returns>MSQuery</returns>
  public string BuildMSQuery(string keywords, string searchScope)
  {
   
StringBuilder msQuery = new StringBuilder();

    // create the main header of the XML string
   
msQuery.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
                 + "<QueryPacket xmlns=\"urn:Microsoft.Search.Query\" "
                 + "Revision=\"1000\">"
                 + "<Query domain=\"QDomain\">"
                 + "<SupportedFormats>"
                 + "<Format>urn:Microsoft. Search.Response.Document.Document"
                 + "</Format></SupportedFormats>");

    // create the actual full-text query
   
msQuery.Append("<Context>"
                
+
"<QueryText language=\"en-US\" type=\"MSSQLFT\">"
                 + "<![CDATA[" +
this.BuildMSsqlftQuery(keywords, searchScope)
                 + "]]> </QueryText></Context>");

    // create the range, page, and number of results
    // to return
    msQuery.Append("<Range><StartAt>1</StartAt><COUNT>20</Count>"
                 + "</Range></Query></QueryPacket>");

    return msQuery.ToString();
  }

The two nodes of an MSQuery after the opening QueryPacket node (Query, and SupportedFormats) should not be modified. The Context node contains the actual search query, which you can change to suit your requirements. The last node, Range, contains directives used to tell the SPS Query Service Web Service how many results to return and at what index to start the result set.

For example, if you displayed 20 results per page and you wanted to show the third page
of results, you'd set the StartAt node to 41 and leave the Count node at 20.

We now have a complete MSQuery string with an included full-text query.

Let's see if our search will now work. Build the Tropical Green project and navigate to
http://www.tropicalgreen.net/. Enter ficus in the search box and click Go. You should see results similar to those in the following image (we'll worry about making it more presentable in a moment):

Every good search engine provides more than just keyword search. Some sites filter by topic and others by product. In our case, we could filter all our results to only the plant catalog, excluding the rest of the site. You would not be able to do this in a user-friendly manner using the controls provided by the MCMS Connector. While a knowledgeable guest could realize they could put in part of the CMS path in one of the advanced search options, it's not straightforward to the typical guest of the site. This is where you can really start to leverage your custom search components.

Let's add a filter to search just our plant catalog:

  1. Open SearchResults.aspx in the Design view, and drag a CheckBox just below our advanced search textbox and assign it the following properties:

     

    Property Value

    CheckBox ID = chkFilterPlantCatalog

    Text = Only Search Plant Catalog


  2. Open the code-behind file for the SearchResults.aspx page and add the following highlighted code to the btnAdvancedSearch_Click() event handler:

    private void btnAdvancedSearch_Click(object sender, System.EventArgs e)
    {
      string keywords = this.txtAdvancedSearch.Text;
      keywords = HttpUtility.UrlEncode(keywords);

     
    string filter = string.Empty;
      if (this.chkFilterPlantCatalog.Checked)
      {
       
    filter = "&filterPlantCatalog=1";
      }

     
     
    Response.Redirect(Request.ApplicationPath
                      + "/SearchResults.
    aspx?keywords=" + keywords + filter);
    }
     
  3. Add the highlighted code below to the BuildMSsqlftQuery() method:

    private string BuildMSsqlftQuery(string keywords, string searchScope) {
      System.Text.StringBuilder mssqlftQuery =
                new System.Text.
    StringBuilder();
      ArrayList whereClause = new ArrayList();

      #region FILTER: keywords
        . . . code continues . . .
      #endregion

      #region FILTER: plant catalog
      // list of keywords to include 
      if ( Request.QueryString["filterPlantCatalog"] != null
           && Request.QueryString["filterPlantCatalog"].ToString() == "1" )
      {
        whereClause.Add("(\"urn:schemas.microsoft.com: htmlinfo:metainfo:PATH"
                      + "\" LIKE '/channels/tropicalgreen/ plantcatalog/%')");
      }
      #endregion

     
     . . . code continues . . . 

    Notice how we are using the urn:schemas.microsoft.com:htmlinfo: metainfo:PATH index property, which is mapped to the CMS Channel Path thanks to the
    SearchPropertyCollection.xml file provided with the MCMS Connector.
  4. Let's see how the filter works. Save your changes and build the Tropical Green project. Once the build is complete, open your browser and navigate to http://www.tropicalgreen.net/TropicalGreen/SearchResults.aspx. Enter ficus in the textbox, check the Only Search Plant Catalog CheckBox, and click the Go button:

Fantastic! We now only see records inside our Tropical Green plant catalog! This gives a good idea of what filtering brings to the table. We could filter by so many things, such as displaying only postings that have been updated in the last month or week. The possibilities are almost endless.

Let's see if we can't clean up those search results by getting rid of the DataGrid and replacing it with a Repeater. At the same time, we'll add filtering of the search results so users will only see postings that they have rights to access.

Although we listed numerous SharePoint index properties in our full text query, we will only use the DAV:href property when analyzing the results in our main results page to obtain a reference to the specified MCMS channel or posting to determine if the user has rights to browse the resource and also to determine and return the actual posting's name and description.

  1. Open the SearchResults.aspx page in Design view. Delete the DataGrid.
  2. Drag a Repeater object onto the page where the DataGrid was. Assign the Repeater an ID of rptSearchResults.
  3. While in Design view, select our new Repeater and open the Properties window. At the top of the window, click the
    Events button to show all possible events we can use. Double-click the box to the right of ItemDataBound to create an empty event handler that will fire every time an item is bound to the repeater. 
  4. Switch back to HTML view for the SearchResults.aspx and scroll to our new Repeater
  5. Add the following highlighted tags into the ItemTemplate of our Repeater:

    <asp:repeater id="rptSearchResults" runat="server">
    <ItemTemplate>
      <asp:Placeholder ID="phdSearchResult" Runat="server" visible="false">

        <p>
          <b><asp:HyperLink ID="hlkResultTitle" Runat="server" /></b>
          <br>
          <asp:Literal ID="litResultDescription" Runat="server" />
        </p>
      </asp:Placeholder>
    </ItemTemplate>
    </asp:repeater>

    Notice the ASP.NET Placeholder we've added surrounding the search result. We'll use
    this to show and hide results that the user does or does not have permission to view.

Now that we have a Repeater filled with some placeholders for the content, we need to modify our data binding, which is still using a DataGrid.

  1. Open the code-behind file for SearchResults.aspx, find the Page_Load() event handler, and modify the code to bind the only DataTable in the DataSet to the Repeater as shown below:

    private void Page_Load(object sender, System.EventArgs e)
    {
      if (Request.QueryString["keywords"] != null
       && Request.QueryString["keywords"].Length >0)
      {
        string keywords = Request.QueryString["keywords"];
        DataSet ds = ExecuteSearch(keywords);
        this.rptSearchResults.Visible = true;
        this.rptSearchResults. DataSource = ds.Tables[0].Rows; 
        this.rptSearchResults.DataBind();  
      }
      else
      {
        this.rptSearchResults.Visible = false;
      }

  2. Before we implement the ItemDataBound event, we need to create a method that will try to obtain the MCMS ChannellItem reference of the URL returned in the results. Add the following method after the Page_Load() event handler we just modified:

    private HierarchyItem GetResult(string url)
    {
      try
      {
        // check if it's a GUID based URL
        if (url.IndexOf("RDONLYRES") >= 0)
        {
          // try to get the GUID if it's a RDONLYRES URL
          string guidRegEx = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-"
                           + "[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
          Regex regex = new Regex(guidRegEx);
          Match m = regex.Match(url);
          if (m.Success)
          {
            return CmsHttpContext.Current.Searches.GetByGuid("{"+m.Value+"}");
          }
        }
        else
        {
          // try to get the object via the URL
          return CmsHttpContext.Current.Searches.GetByUrl(url);
        }
        // if this point reached, unknown URL
        return null;
      }
      catch
      {
        return null;
      }

  3. Now, find the rptSearchResults_ItemDataBound() event handler. We need to trap the event when it's binding a data item to the ItemTemplate or AlternateItemTemplate in the Repeater. Then, we'll get a reference to the data item being bound to the template, in our case a DataRow, and get references to the ASP.NET objects we added to the template. Finally, we'll use the data in the DataRow to populate the properties of our controls. Here's what our completed ItemDataBound() event handler will look like:

    private void rptSearchResults_ItemDataBound(object sender, System.Web.UI.WebControls. RepeaterItemEventArgs e)
    {
      if ( (e.Item.ItemType == ListItemType.AlternatingItem)
        || (e.Item.ItemType == ListItemType.Item) )
      {
        // get a reference to the datarow being bound
        DataRow row = e.Item.DataItem as DataRow;
        HierarchyItem hi = GetResult(row[0].ToString());

        // get references to all the ASP.NET objects
        PlaceHolder resultContainer = e.Item.FindControl("phdSearchResult")
              as PlaceHolder;
        HyperLink resultTitle = e.Item.FindControl("hlkResultTitle")
              as HyperLink;
        Literal resultDesc = e.Item.FindControl("litResultDescription")
              as Literal;

        // if the URL doesn't resolve to an MCMS resource,
        // output it to the results
        if (hi != null)
        {
          // user has rights to this item so display it.
          resultContainer.Visible = true;

          // use values in DataRow to populate objects
          resultDesc.Text = hi.Description;
          if (hi is ChannelItem)
          {
            resultTitle.Text = (hi as ChannelItem).DisplayName;
            resultTitle.NavigateUrl = (hi as ChannelItem).Url;
          }
          else
          {
            if (hi is Resource)
              resultTitle.NavigateUrl = (hi as Resource).Url; 
            resultTitle.Text = hi.Name;
          }
        }
      }
    }

The final result looks something like this:

You'll see that the description field may not have exactly what we're looking for, but this technique lets us customize the search result list to our hearts' content. You could pull the description of the posting straight out of the indexed values, provided you exposed the page description using the SearchPropertyCollection.xml file. Or you could even have an HtmlPlaceholder called "Search Description" in all your templates that content owners could use to enter a description to show when the posting appears in search results.

Summary

 

In this chapter we discussed a few of the options available to MCMS developers for adding search functionality to their sites. We proceeded to take an in-depth look at the searching features built into SharePoint Portal Server and how they can be leveraged as a back-end search workhorse for an MCMS site. Before we could start adding the search functionality, we had to make a few changes to our site and templates, as well as build an index using SharePoint to crawl our site.

Once our site was configured for index crawls and SharePoint was configured to crawl our site and build an index, we explored in detail two options for adding search functionality to the Tropical Green site using the SharePoint crawler:

  • First we implemented search using the MCMS Connector for SharePoint Technologies, an out-of-the-box solution.

Then, we built our own solution using the SharePoint Query Service Web Service and custom full text T-SQL queries to provide search filters and customized results.

Advanced Microsoft Content Management Server Development:

Working with the Publishing API, Placeholders, Search, Web Services, RSS, and SharePoint Integration

Following on from Building Websites with Microsoft Content Management Server (Packt Publishing, January 2005, ISBN 1-904811-16-7), this book takes MCMS development to a higher level of both power and integration. Like its predecessor, this book is packed with code examples and never-before-seen secrets of MCMS.

Microsoft Content Management Server 2002 is a dynamic web publishing system with which you can build websites quickly and cost-efficiently. MCMS provides the administration, authoring, and data-management functionality and you provide the website interface, logic, and workflow. Microsoft SharePoint Portal Server (SPS) also features in this book. SPS 2003 enables enterprises to deploy an intelligent portal that seamlessly connects users, teams, and knowledge so that people can take advantage of relevant information across business processes to help them work more efficiently.

You've mastered the basics of MCMS, and have set up your own MCMS installation. But you've only scratched the surface. This book is your gateway to squeezing every penny from your investment in MCMS and SPS, and making these two applications work together to provide an outstanding richness of content delivery and easy maintainability.

What This Book Covers

Chapter 1 demonstrates the power of the MCMS Publishing API (PAPI) by building the CMS Explorer administration tool to manage an MCMS website. Chapter 2 builds on the CMS Explorer by adding the ability to manage channels and postings. Chapter 3 looks at the creation, submission, copying, moving, and deletion of templates, template galleries, and resources through the PAPI.

In Chapter 4, you will learn how to prepare postings for search indexing. We look at several techniques that can improve the accuracy of search results and optimize your search engine.

SharePoint Portal Technologies complement MCMS by providing collaboration, document libraries, and searching to the robust publishing workflow of MCMS. Chapter 5 takes you through the process of adding searching to an MCMS Site using SharePoint Portal Server, either using the MCMS Connector for SharePoint Technologies or by building your own solution.

Chapter 6 demonstrates how you can use the MCMS Connector for SharePoint to build your own components to share content between MCMS and SharePoint. Chapter 7 shows how you can build Web Parts that integrate content from MCMS on a SharePoint portal site.

Chapter 8 discusses five custom placeholder controls that provide some frequently requested features that are not present in the default controls: a date-time picker placeholder control, a placeholder control that permits multiple attachments, an image-rotator placeholder control, a placeholder control to store all kinds of HTML tags, and a DataGrid placeholder control.

Validation of content is a key requirement in many MCMS implementations. Chapter 9 looks at how you can apply ASP.NET validation techniques to each of the out-of-the box placeholder controls.

Static pages are often used in direct mailers, help files, and even for archiving purposes. Chapter 10 discusses a couple of techniques that you can use to create static snapshots of postings.

The authoring experience doesn't always need to be through the browser. One author-friendly way of maintaining content is detailed in Chapter 11. In this chapter, we leverage the power of InfoPath to quickly create a GUI that allows authors to submit content directly from Microsoft Word, with the help of MCMS Web Services.

Since the release of MCMS in 2002, a lot of technologies have changed. Syndication of websites using RSS is the norm, and to capitalize on this, Chapter 12 takes you through the steps involved in creating a dynamic RSS feed of your website's recent changes.

Finally, Chapter 13 provides many invaluable insider's tips and tricks for MCMS, as well as solutions to common MCMS issues, including gems such as how to revert a posting to a previous version, change a posting's template, build a recycle bin, and export resource gallery items using the Site Deployment API.

Where to buy this book

You can buy Advanced Microsoft Content Management Server Development from the Packt Publishing website: http://www.packtpub.com/more_mcms/book.

Free shipping to the US, UK, Europe, Australia, New Zealand & India.

Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and most internet book retailers.

blog comments powered by Disqus
WINDOWS SCRIPTING ARTICLES

- More Windows Scripting Workarounds from Nilpo
- Overloading Methods and More in VBScript
- Improving MFC for Windows Vista
- Regular Expressions in VBScript
- Working with Dates in WMI
- Completing Calendars with VBScript Date Func...
- Building Calendars with VBScript Date Functi...
- Working With Dates and Times in VBScript
- Designing WCF DataContract Classes Using the...
- Understanding Dates and Times in VBScript
- Working With Arrays in VBScript
- Compressed Folders in WSH
- Using .NET Interops in VBScript
- Nilpo`s Scripting Secrets, Vol I
- Database operations using Silverlight 2.0 WC...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 6 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials