Sharepoint Search from Tafiti

Posted by: Clarity Blogs: ASP.NET, on 20 Dec 2007 | View original | Bookmarked: 0 time(s)

I read a post on Angus Logan's blog about using Tafiti to provide a UX on top of Enterprise Search.  I've never used the SharePoint Search SDK before so I thought I'd give it a try.

The code is pretty hacked together since I just wanted to see how it worked. 

Screenshot of Tafiti running in a page viewer web part against my dev machine.  The code is using impersonation to query our MOSS server.

 

image

 

Screenshot of the classic tree view.

image

 

To get started you need to download the Tafiti source from CodePlex and follow the setup guide.

Open the solution in VS 2008.  Although solution didn't work for me.  I had to remove the projects and re-add them.  I also changed the target framework type to 3.0.

Add a web reference to you sharepoint search web service at <server_name>/_vti_bin/search.asmx

 

image

As per Angus's blog post, you really only have to alter code in the Search.aspx.cs page to change the search engine to SharePoint.

 

   1:  private void SoapSearch(SourceType sourceType, string query, int first, int count)
   2:      {
   3:          try
   4:          {
   5:              SourceRequest[] sr = new SourceRequest[1];
   6:              sr[0] = new SourceRequest();
   7:              sr[0].Source = sourceType;
   8:              sr[0].Offset = first;
   9:              sr[0].Count = count;
  10:              sr[0].ResultFields = GetResultFieldMask(sourceType);
  11:   
  12:              //SearchRequest request = new SearchRequest();
  13:              //request.Query = query;
  14:              //request.Requests = sr;
  15:              //request.SafeSearch = SafeSearchOptions.Strict;
  16:              //request.AppID = SettingsWrapper.LiveSearchAppID;
  17:              //request.CultureInfo = "en-US";
  18:   
  19:              //if (sourceType == SourceType.PhoneBook)
  20:              //{
  21:              //    // Using Redmond as the search location.
  22:              //    request.Location = new Location();
  23:              //    request.Location.Longitude = Double.Parse("-122.33482360839846");
  24:              //    request.Location.Latitude = Double.Parse("47.6082462871061");
  25:              //    request.Location.Radius = Double.Parse("5");
  26:              //}
  27:   
  28:              //MSNSearchService searchService = new MSNSearchService();
  29:              //SearchResponse searchResponse;
  30:              //searchResponse = searchService.Search(request);
  31:   
  32:              //---------SharePoint Search Code------
  33:   
  34:              string qXMLString = "<QueryPacket xmlns='urn:Microsoft.Search.Query'>" +
  35:                  "<Query><SupportedFormats><Format revision='1'>" +
  36:                  "urn:Microsoft.Search.Response.Document:Document</Format>" +
  37:                  "</SupportedFormats><Context><QueryText language='en-US' type='STRING'>" +
  38:                  query +
  39:                  "</QueryText></Context></Query></QueryPacket>";
  40:   
  41:   
  42:              System.Security.Principal.WindowsImpersonationContext impersonationContext;
  43:              impersonationContext =
  44:                  ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
  45:   
  46:              SPSearch.QueryService queryService = new SPSearch.QueryService();
  47:              queryService.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
  48:              System.Data.DataSet queryResults = queryService.QueryEx(qXMLString);
  49:   
  50:              impersonationContext.Undo();
  51:   
  52:              //--------------------------------
  53:   
  54:              LiveXmlSearchResults result = CreateLiveXmlFromMossSearchResults(queryResults);
  55:   
  56:              JavaScriptSerializer serializer = new JavaScriptSerializer();
  57:              string json = serializer.Serialize(result);
  58:              byte[] jsonUtf8 = System.Text.Encoding.UTF8.GetBytes(json);
  59:   
  60:              Response.StatusCode = 200;
  61:              Response.ContentType = "text/javascript";
  62:              Response.OutputStream.Write(jsonUtf8, 0, jsonUtf8.Length);
  63:          }
  64:          catch (SoapException e)
  65:          {
  66:              throw new HttpException((int)HttpStatusCode.InternalServerError, "Internal Server Error", e);
  67:          }
  68:          catch (WebException e)
  69:          {
  70:              throw new HttpException((int)HttpStatusCode.InternalServerError, "Internal Server Error", e);
  71:          }
  72:      }

 

To make a search against sharepoint you just need to call the QueryEx method off of the QueryService from your web reference.  MSDN has an overview of the QueryEx method here.

The next step is to reformat the dataset returned from MOSS into the Live search results format.  Like Angus mentioned, converting the result into the LiveXmlSearchResults allows you to reuse the JavaScriptSerializer and existing JavaScript code in Silverlight.

 

These functions are a little messy :) Not all of the results had a description so I pulled the HitHighlightedSummary from the dataset and removed some of the extra tags it added.

 

   1:      private LiveXmlSearchResults CreateLiveXmlFromMossSearchResults(System.Data.DataSet mossSearchResults)
   2:      {
   3:          LiveXmlSearchResults searchResults = new LiveXmlSearchResults();
   4:          searchResults.searchresult.documentset._source = "FEDERATOR_MONARCH";
   5:          searchResults.searchresult.documentset._count = mossSearchResults.Tables[0].Rows.Count.ToString();
   6:          searchResults.searchresult.documentset._start = "0";
   7:          searchResults.searchresult.documentset._total = mossSearchResults.Tables[0].Rows.Count.ToString();
   8:   
   9:          LiveXmlResult[] results = ConvertMOSSWebResults(mossSearchResults.Tables[0]);
  10:   
  11:          if (results != null)
  12:              searchResults.searchresult.documentset.document = (results.Length > 1) ? (object)results : (object)results[0];
  13:   
  14:          return searchResults;
  15:      }
  16:   
  17:      private static LiveXmlResult[] ConvertMOSSWebResults(System.Data.DataTable mossSearchResultsTable)
  18:      {
  19:          LiveXmlWebResult[] results = new LiveXmlWebResult[mossSearchResultsTable.Rows.Count];
  20:   
  21:          for (int i = 0; i < mossSearchResultsTable.Rows.Count; i++)
  22:          {
  23:              LiveXmlWebResult result = new LiveXmlWebResult();
  24:              string description = string.Empty;
  25:              description = 
  26:                   GetDescription(mossSearchResultsTable.Rows["Description"].ToString(), mossSearchResultsTable.Rows["HitHighlightedSummary"].ToString());
  27:              result.title = mossSearchResultsTable.Rows["Title"].ToString();
  28:              result.desc  = description;
  29:              result.url = mossSearchResultsTable.Rows["Path"].ToString();
  30:              results = result;
  31:          }
  32:          return results;
  33:      }
  34:   
  35:      private static string GetDescription(string description, string hitHighlightedSummary)
  36:      {
  37:          string strippedText = string.Empty;
  38:   
  39:          if (string.IsNullOrEmpty(description))
  40:          {
  41:              Regex regEx = new Regex("<[^>]*>", RegexOptions.IgnoreCase);
  42:              strippedText = regEx.Replace(hitHighlightedSummary, "...");
  43:              return strippedText;
  44:          }
  45:          else
  46:              return description;
  47:      }

 

Next I think I'll try integrating it into MOSS to be an actual page in the search center.  I'd also like to change the News/Phonebook/Web search option carousal to have it do some different searches like People, Office Docs, etc.   Also remove the Windows Live functionality and misc. extra hyperlinks. Oh and fix the range / start offset so it pages properly.  When I started this an hour ago I didn't really realize the difference between Query and QueryEx [Maybe I should have read those docs I linked to :) ].  Looks like I might have to use QueryEx so get some of the extra info like total number of records.  Oh maybe add in the relevance / thumbnail icons for filetypes.  Well it's a prototype so I'll probably just start over anyway.

 

Technorati Tags: MOSS,SharePoint,Tafiti,Silverlight,Angus LoganShare this post: Email it! | bookmark it! | digg it! | reddit!

Advertisement
Free Agile Project Management Tool from Telerik
TeamPulse Community Edition helps your team effectively capture requirements, manage project plans, assign and track work, and most importantly, be continually connected with each other.
Category: Silverlight | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 2959 | Hits: 23

Similar Posts

  • Make SharePoint 2007 Act Like SharePoint 2010, Updated more
  • Dissecting Lucene.net storage: Documents and Fields more
  • Lucene.net: the main concepts more
  • WebAii Testing Framework: From HTML to XAML and Back -- RadHtmlPlaceholder more
  • Speaking at Chicago SharePoint User Group on September 10th 2009 more
  • SharePoint Search-as-You-Type with jQuery more
  • Linq: Beware of the 'Access to modified closure' demon more
  • Sharepoint for Developer Series by Kirk Evans more
  • Using Search Folders in Outlook 2007 for GTD more
  • Setting up for Watin testing more

News Categories

.NET | Agile | Ajax | Architecture | ASP.NET | BizTalk | C# | Certification | Data | DataGrid | DataSet | Debugger | DotNetNuke | Events | GridView | IIS | Indigo | JavaScript | Mobile | Mono | Patterns and Practices | Performance | Podcast | Refactor | Regex | Security | Sharepoint | Silverlight | Smart Client Applications | Software | SQL | VB.NET | Visual Studio | W3 | WCF | WinFx | WPF | WSE | XAML | XLinq | XML | XSD