Building an IE8 Visual Search Suggestion Provider for my Twitter Friends

17 בדצמבר 2008

תגובה אחת

Building an IE8 Visual Search Provider for my Twitter Friends


imageWith the upcoming release of Internet Explorer 8, one of the new features in it that I am most excited about is the Visual Search Suggestions.


In this post I will build a Visual Search Suggestion Provider that displays a list of my twitter friends with their current status and profile image as I type their name in the search box.


You can download the source code of the complete version of this guide.


This guide is based on the Search Provider Extensibility in Internet Explorer page on MSDN.


1. Building a WCF REST Service


Create a new Empty Web Site, and call it TwitterFriendsSearch.


Visual Search Suggestion in Internet Explorer 8


Add a new Item of type WCF Service, and call it SuggestService.svc.


Visual Search Suggestion in Internet Explorer 8


imageThis creates the following files in the web site:



  • ISuggestService.cs – The Service Contract. Defines the signature of the service operations.

  • SuggestService.cs – The Service Implementation.

  • SuggestService.svc – The service endpoint.

  • Web.config – Configuration settings for the WCF Service.

Change the service contract definition (ISuggestService.cs) to the following:


[ServiceContract]
public interface ISuggestService
{
  [OperationContract]
  string Search(string friend);
}

Open the service implementation file (SuggestService.cs) and implement the service. For now, we will give it a basic implementation, and later on we will change it.


public class SuggestService : ISuggestService
{
  public string Search(string friend)
  {
    return "Hello, " + friend;
  }
}

In order to provide the REST support, add the necessary WebGet attribute above the service operation.


[OperationContract]
[WebGet(UriTemplate = "/Search?q={friend}",
        BodyStyle = WebMessageBodyStyle.Bare)]
string Search(string friend);

Change the configuration file of the WCF Service (web.config) to enable REST support. Under System.serviceModel section in the configuration file, locate the behaviors node, and add a new Endpoint behavior:


<system.serviceModel>
  …
  <behaviors>
    …
<
endpointBehaviors>
      <behavior name="REST">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
    …
  </behaviors>
  …
</system.serviceModel>

In the same section, locate the service definition and the first endpoint definition. Change the binding to webHttpBinding (instead of wsHttpBinding) and add apply the endpoint behavior:


<services>
  <service behaviorConfiguration="SuggestServiceBehavior" 
           name="SuggestService">
    <endpoint address="" 
              binding="webHttpBinding" 
              contract="ISuggestService" 
              behaviorConfiguration="REST" />
  </service>
</services>

Run the project, and navigate to the .svc file. Then, add the UriTemplate like you defined on the service with a friend name to search:



http://localhost:50434/TwitterFriendsSearch/SuggestService.svc/search?q=guy


You should get a response saying "hello, guy”.


2. Returning a Search Suggestion


According to the MSDN Page I linked to above, the final Visual Search Suggestion response should look like this (this response corresponds to the search suggestion picture I showed at the beginning of this post).


<?xml version="1.0" encoding="utf-8" ?>
<SearchSuggestion>
  <Query>guy</Query>
  <Section>
    <Item>
      <Text>guyhaim</Text>
      <Description>@rohitbhargava http://tinyurl.com/6m9e4g</Description>
      <Url>http://twitter.com/home</Url>
      <Image source="http://…normal.jpg" 
height="48" width="48" alt="guyhaim" />
    </Item>
    <Item>
      <Text>Guy Malachi</Text>
      <Description>Yahoo toolbar looks kinda weird.</Description>
      <Url>http://twitter.com/home</Url>
      <Image source="http://…normal.jpg" 
height="48" width="48" alt="guym" />
    </Item>
    <Item>
      <Text>guy zohar</Text>
      <Description>switch screen</Description>
      <Url>http://twitter.com/home</Url>
      <Image source="http://…normal.jpg" 
height="48" width="48" alt="guyzo" />
    </Item>
    <Item>
      <Text>guyzarz</Text>
      <Description>@ekampf May it rest in peace, in one piece.</Description>
      <Url>http://twitter.com/home</Url>
      <Image source="http://…normal.jpg" 
height="48" width="48" alt="guyzarz" />
    </Item>
  </Section>
</SearchSuggestion>

Create the following classes to represent the response elements, and use the Xml Serialization attributes in order to later serialize them into the required output.


// Image.cs 
[XmlType]
public class Image
{
  [XmlAttribute(AttributeName="source")]
  public string Source { get; set; }
 
  [XmlAttribute(AttributeName = "height")]
  public int Height { get; set; }
 
  [XmlAttribute(AttributeName = "width")]
  public int Width { get; set; }
 
  [XmlAttribute(AttributeName = "alt")]
  public string Alt { get; set; }
}

// Item.cs 
[XmlType]
public class Item
{
  [XmlElement]
  public string Text { get; set; }
 
  [XmlElement(IsNullable=false)]
  public string Description { get; set; }
 
  [XmlElement(IsNullable = false)]
  public string Url { get; set; }
 
  [XmlElement(IsNullable = false)]
  public Image Image { get; set; }
}


// SearchSuggestion.cs
[XmlRoot(Namespace="")]
public class SearchSuggestion
{
  public SearchSuggestion()
  {
    this.Section = new List<Item>();
  }
 
  [XmlElement]
  public string Query { get; set; }
 
  [XmlArray]
  public List<Item> Section { get; set; }
}

Change the service contract to return a SearchSuggestion response instead of a string. Also add the XmlSerializerFormat attribute to make sure the response is being serialized to XML.



[ServiceContract]
public interface ISuggestService
{
  [OperationContract]
  [WebGet(UriTemplate = "/Search?q={friend}",
          BodyStyle = WebMessageBodyStyle.Bare)]
  [XmlSerializerFormat]
  SearchSuggestion Search(string friend);
}

Change the service implementation to return a SearchSuggestion with default values.


public SearchSuggestion Search(string friend)
{
  SearchSuggestion suggestion = new SearchSuggestion
  {
    Query = friend
  };
 
  suggestion.Section.Add(new Item
  {
    Text = friend,
    Description = "Hello, " + friend,
    Url = "http://blogs.microsoft.co.il/blogs/bursteg",
    Image = new Image
    {
      Source = "http://tinyurl.com/burstegprofileimage",
      Alt = "Guy Burstein",
      Width = 48,
      Height = 48
    }
  });
 
  return suggestion;
}

If you now run the project and navigate to the same url as above, you should get this response:



<?xml version="1.0" encoding="utf-8" ?>
<SearchSuggestion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>omer</Query>
  <Section>
    <Item>
      <Text>omer</Text>
      <Description>Hello, omer</Description>
      <Url>http://blogs.microsoft.co.il/blogs/bursteg</Url>
      <Image source="http://tinyurl.com/burstegprofileimage" 
             height="48" 
             width="48" 
             alt="Guy Burstein" />
    </Item>
  </Section>
</SearchSuggestion>

3. Adding the Search Provider to Internet Explorer


Add a new Xml file to the web site, and call it FriendsSuggestion.xml. This file contains the provider details for the browser, and should contain the following contents:



<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
  <ShortName>Friends Search</ShortName>
  <Url type="text/html"
       template="http://localhost:50434/TwitterFriendsSearch/
SuggestService.svc/search?q={searchTerms}
" />
  <Url type="application/x-suggestions+xml"
       template="http://localhost:50434/TwitterFriendsSearch/
SuggestService.svc/search?q={searchTerms}
" />
  <Image height="16"
         width="16"
         type="image/icon">http://twitter.com/favicon.ico</Image>
</OpenSearchDescription>

Add a Default.aspx page to the web site. In this file, create a JavaScript function that registers the new provider within the browser:


<script type="text/javascript">
function Register() {
  window.external.AddSearchProvider('FriendsSuggestion.xml');
}
</script>

Create an HTML button, and execute the Register method when it is clicked.


<form id="form1" runat="server">
<div>
  <button onclick='Register();'>Click Here</button>
</div>
</form>

Run the project and navigate to Default.aspx. Click the button to register the provider within the browser, and make sure that the search suggestion option is checked.


Visual Search Suggestion in Internet Explorer 8


Now, go to the search box, click the friends search (the one with the twitter icon) and search for any keyword. What you should see is the static Visual Search Suggestion we’ve just created.


Visual Search Suggestion in Internet Explorer 8


4. Getting Twitter Friends as Search Results


Now, I want to return live results from my friends list from Twitter, but the following section can be changed according to any source of your choice.


In the service implementation, remove the default assignment of the section property of the search suggestion element, and perform a HTTP call the Twitter to get the list of your friends (replace “bursteg” with your Twitter account)


string url = string.Format(
"http://twitter.com/statuses/friends/{0}.xml", "bursteg");
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseString = reader.ReadToEnd();
reader.Close();

Then, use LINQ to XML to parse the response, and get the list of friends that corresponds to the search creteria:


XDocument document = XDocument.Parse(response, LoadOptions.None);
var query = from e in document.Root.Descendants("user")
            where e.Element("name").Value.Contains(friend) ||
                  e.Element("screen_name").Value.Contains(friend)
            select new Item
            {
 
              Text = e.Element("name").Value,
              Image = new Image
                          {
                            Source = e.Element("profile_image_url").Value,
                            Alt = e.Element("screen_name").Value,
                            Width = 48,
                            Height = 48
                          },
              Description = (e.Element("status") == null ? "" : 
HttpUtility.HtmlDecode(e.Element("status").Element("text").Value)),
              Url = (String.IsNullOrEmpty(e.Element("url").Value) ? 
"http://twitter.com/home" :
e.Element("url").Value)
            };

Finally, add those items to the search suggestion and return it.


suggestion.Section.AddRange(query);

The full version of the Search method should look like this:


public SearchSuggestion Search(string friend)
{
  SearchSuggestion suggestion = new SearchSuggestion();
  suggestion.Query = friend;
 
  string url = string.Format("http://twitter.com/statuses/friends/{0}.xml", "bursteg");
  HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
  WebResponse response = request.GetResponse();
  StreamReader reader = new StreamReader(response.GetResponseStream());
  string responseString = reader.ReadToEnd();
  reader.Close();
 
  XDocument document = XDocument.Parse(responseString, LoadOptions.None);
  var query = from e in document.Root.Descendants("user")
              where e.Element("name").Value.Contains(friend) ||
                    e.Element("screen_name").Value.Contains(friend)
              select new Item
              {
 
                Text = e.Element("name").Value,
                Image = new Image
                {
                  Source = e.Element("profile_image_url").Value,
                  Alt = e.Element("screen_name").Value,
                  Width = 48,
                  Height = 48
                },
                Description = (e.Element("status") == null ? "" : 
HttpUtility.HtmlDecode(e.Element("status").Element("text").Value)),
                Url = (String.IsNullOrEmpty(e.Element("url").Value) ? 
"http://twitter.com/home" :
e.Element("url").Value)
              };
 
  suggestion.Section.AddRange(query);
  return suggestion;
}

Now, if you search for a friend, you’ll get his name, profile image and current status with the Visual Search Suggestion in Internet Explorer 8.


image


You can download the source code of the complete version of this guide.


Enjoy!

הוסף תגובה
facebook linkedin twitter email

תגובה אחת

  1. Alina-System1 באוגוסט 2009 ב 0:55

    This brings me to an idea:…

Comments are closed.