September 2012 - Posts

I’ve recently taken an interest to building Windows Store Apps (aka Windows 8 Metro).  Not because I think I can get rich in the Windows Store but because I think it provides a unique way to present SharePoint data.  If you’re like me, you probably assumed Windows Store App development was just like .NET Framework 4.5 development.  You would be wrong.  The .NET Framework is provided by a single assembly reference called .NET for Windows Store Apps.  It has many of the familiar classes that you have come to expect.  My initial thinking was that I could use the SharePoint Client Object Model directly from my app.  That thinking was also wrong.  It turns out that the Client Object Model has a dependency on System.Web.Service.dll which does not exist in .NET for Windows Store Apps.  Simply put, Window Store Apps only support WCF references.  This means that the REST API is now our best choice.

When it comes to Windows Store Apps, you have a few choices on which programming language to use.  Modern JavaScript is not my strong point, so I am going to demonstrate using C#.  Before we dig into the C# code though, we’ll take a look at how to construct the REST URL.  This article on MSDN does a great job explaining the details of how the URL is built.  Essentially we start with the URL to our site (i.e.: http://server/site) and append /_api/web/lists to it along with a method to get a particular list by title, getbytitle.  To get the items of the list we append /items to it.   In my case, I want to pull the tasks list of a site so it would look something like this.

http://server/site/_api/web/list/getbytitle(‘tasks’)/items

You can type this right into your browser and see the XML that the REST API returns.  Here’s an example.

RESTAPIListsBrowser

There is a lot of XML to take in there.  We’re particularly interested in the content element contain in each entry element.  This has the data from our list items.  However, we can reduce the amount of XML returned significantly by using the $select parameter on the REST URL.  In my case I am going to select a few common fields such as Title, DueDate, and Status.  Here is what the URL looks like now.

http://server/site/_api/web/list/getbytitle(‘tasks’)/items?$select=Title,DueDate,Status,PercentComplete

RESTAPIListsWithSelectBrowser

You’ll notice that the results are much more manageable now.  We’ll talk about how we can use LINQ to XML here shortly to parse this data into something usable from our Windows Store app. 

Now let’s look at the code that is required to get the data in our app.  Start by creating a new Windows Store App in Visual Studio 2012.  You can do this by choosing your language (C#) and then Windows Store –> Blank App (XAML).

VS12NewWindowsStoreApp

If this is the first Windows Store App you have started in Visual Studio, you will be prompted for your Windows Live credentials.  This allows you to get a certificate so that you can build apps locally.  In our app, we want to bind data, so I am going to create a new Items Page.  This template has many of the components you need to get started quickly with data binding.

VS12NewItemsPage

When adding the page, you will be prompted to add some dependent files.  Click yes and then you should see your design surface.  Now, open the code-behind of your Items page.  In the LoadState method, we will start the process of retrieving our data and binding it.  We rely on some asynchronous calls to get data from REST, so we will need to put this data in another method and use the async keyword.

protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)

{

    // TODO: Assign a bindable collection of items to this.DefaultViewModel["Items"]

    BindData();

}

 

private async void BindData()

{

 

}

Before we start writing the method though, we need to include a few using statements.

using System.Net;

using System.Net.Http;

using System.Xml;

using System.Xml.Linq;

If you have looked at any of the other C# examples for working with the REST API, you will know they are heavily dependent on the HttpWebRequest object.  However, with Windows Store Apps, we have to use HttpClient instead. We’ll start by defining our REST URL from up above.

string restUrl = "http://server/_api/lists/getbytitle('tasks')/items?$select=Title,DueDate,Body,Status,PercentComplete";

To handle authentication we first need to create an HttpClientHandler object.  We want to automatically use the credentials of the currently logged in user so this is required.  To enable this, just set UseDefaultCredentials to true.  There are also other settings required which we’ll talk about below.

HttpClientHandler httpClientHandler = new HttpClientHandler();

httpClientHandler.UseDefaultCredentials = true;

We can now create the HttpClient object by passing the HttpClientHandler to the constructor.

HttpClient client = new HttpClient(httpClientHandler);

We then need to tell the REST API, that we want the result back as ATOM / XML as opposed to JSON.  We do this by setting a few headers.

client.DefaultRequestHeaders.Add("Accept", "application/atom+xml");

client.DefaultRequestHeaders.Add("ContentType", "application/atom+xml;type=entry");

Now, we can send the request to SharePoint and wait for a response.  We use the await keyword on the GetAsync() method which is why we needed the async keyword on the method signature.  The EnsureSuccessStatusCode() method simply throws an exception if a valid 200 HTTP response is not received.

var response = await client.GetAsync(restUrl);

response.EnsureSuccessStatusCode();

At this point our data has been received back at the client from SharePoint.  Now we need to begin the fun process of parsing it and binding it.  We get the raw string XML data with the following method (also asynchronous).  You could run the app at this point (with a few tweaks) if you wanted to see it in the debugger but we haven’t done anything wit the data yet.

string responseBody = await response.Content.ReadAsStringAsync();

Now we need to read the XML into an XDocument object so that we can use LINQ to XML to parse it.

StringReader reader = new StringReader(responseBody);

XDocument responseXml = XDocument.Load(reader, LoadOptions.None);

Now we have the data into something queryable.  However, what we really need is a custom object that we can bind to.  If you look back at the XML, you might have noticed a few namespaces in use in the XML document.  We need to define those or our queries will never work.

XNamespace atom = "http://www.w3.org/2005/Atom";

XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";

XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";

Now, we can use LINQ to XML to select the data into a new anonymous type.  If you look at the XML again, we want to query entry elements using the Descendants() method and then the actual values we want are inside the nested Content and then Properties elements.  The data is heavily nested so it makes our LINQ to XML a little messy.  It’s not too bad though.  For the non-string values, I parse the data into the type that I want it (i.e.: DateTime).

var items = from item in responseXml.Descendants(atom + "entry")

            select new

            {

                Title = item.Element(atom + "content").Element(m + "properties").Element(d + "Title").Value,

                DueDate = DateTime.Parse(item.Element(atom + "content").Element(m + "properties").Element(d + "DueDate").Value),

                Status = item.Element(atom + "content").Element(m + "properties").Element(d + "Status").Value,

                PercentComplete = decimal.Parse(item.Element(atom + "content").Element(m + "properties").Element(d + "PercentComplete").Value)

            };

Now, we have data that can be bound to the GridView / ListView on the Items Page.  To bind we assign our data source as follows:

this

.DefaultViewModel["Items"] = items;

Just like Windows Phone and SharePoint apps need to declare the capabilities of the application, Windows Store Apps are no different.  To do this, open Package.appmanifest.  In our case, we need to declare that we intend to communicate over the internal network (Private Networks) and that we need Enterprise Authentication.  The latter allows the app to authenticate with the current user’s domain credentials automatically.  If you don’t have this capability set, you are guaranteed a 401 Access Denied or Unable to connect to remote server error.

Windows8ProjectCapabilities

We can now run the app.  However, there is one last thing we need to do.  We need a way to navigate to the TaskItemsPage that we created.  It loads MainPage by default.  Without getting to deep into how Windows Store app navigation works, we’ll just throw a button on the MainPage and then navigate to the TaskItemsPage when clicked.  You can drag and drop a button onto the MainPage using the designer.  Double click on it and it will create the event handling method.  Then we use Frame.Navigate() and pass it the type of page we want to go to, TaskItemsPage.  Here is the code.

private void Button_Click_1(object sender, RoutedEventArgs e)

{

    Frame.Navigate(typeof(TasksItemsPage));

}

Run your app, and click on the button to navigate to your TaskItemsPage.  If all goes well, you won’t receive any errors and you’ll see a page like the screen below.  Note, that your application doesn’t currently have any way to exit.  To get out you either need to Alt+Tab or move your mouse to the Top-Left corner of the screen to switch to the desktop.

Windows8TasksItemsPage

This is great, but we’re not using all of our data yet.  By default, it will bind the Title for us.  However, we want to display some of our additional fields though.  To do this, we can create a DataTemplate.  We need to look into how it works first though.  Locate the GridView in your XAML file.  It should look something like this.

<GridView

    x:Name="itemGridView"

    AutomationProperties.AutomationId="ItemsGridView"

    AutomationProperties.Name="Items"

    TabIndex="1"

    Grid.RowSpan="2"

    Padding="116,136,116,46"

    ItemsSource="{Binding Source={StaticResource itemsViewSource}}"

    ItemTemplate="{StaticResource Standard250x250ItemTemplate}"

    SelectionMode="None"

    IsSwipeEnabled="false"/>

Notice the ItemTemplate and how it is bound to Standard250x250ItemTemplate.  This template can actually be found in StandardStyles.xaml

<DataTemplate x:Key="Standard250x250ItemTemplate">

    <Grid HorizontalAlignment="Left" Width="250" Height="250">

        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">

            <Image Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>

        </Border>

        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">

            <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>

            <TextBlock Text="{Binding Subtitle}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>

        </StackPanel>

    </Grid>

</DataTemplate>

If you look at what it is binding, it’s looking for fields Image, Title, and Subtitle.  We don’t have an image, so we can get rid of that.  In its place, we’ll add the other fields in our dataset.  We don’t want to edit the out-of-the-box template, so we can copy this snippet and add it to the Pages.Resources element in our TaskItemsPage.xaml.  I then changed its name to TaskItemTemplate and added the remaining fields.

<DataTemplate x:Key="TaskItemTemplate">

    <Grid HorizontalAlignment="Left" Width="250" Height="250">

        <StackPanel VerticalAlignment="Top" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">

            <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>

            <TextBlock Text="{Binding DueDate}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>

            <TextBlock Text="{Binding PercentComplete}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>

            <TextBlock Text="{Binding Status}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>

        </StackPanel>

    </Grid>

</DataTemplate>

Now we just need to change the template name in the GridView to use the TaskItemTemplate.

<GridView

    x:Name="itemGridView"

    AutomationProperties.AutomationId="ItemsGridView"

    AutomationProperties.Name="Items"

    TabIndex="1"

    Grid.RowSpan="2"

    Padding="116,136,116,46"

    ItemsSource="{Binding Source={StaticResource itemsViewSource}}"

    ItemTemplate="{StaticResource TaskItemTemplate}"

    SelectionMode="None"

    IsSwipeEnabled="false"/>

Run the app again and you’ll now have your custom fields bound.  It should look something like this.

Windows8TasksItemsPageCustomTemplate

The DueDate and PercentComplete are not formatted in this case.  I won’t cover that today, but if you look at the Blog Reader example, it explains the techniques you can use to do cool formatting.  The Data Binding article goes into a lot of detail if you want to learn all of the ways you can bind data too.  If you want a good tutorial to start from scratch on a Windows Store App, see the Hello, World example.

This turned out to be quite the long blog post.  I hope you find it useful.  If you find this interesting and you are going to be at SharePoint Conference 2012 in November (SPC12), you should be sure and attend my session Bringing SharePoint to the Desktop: Building Windows Store Apps with SharePoint 2013 (SPC025).

Follow me on twitter @coreyroth.

I have the honor of speaking again at SharePoint Conference this year and I think this one is going to be a great one.  I have two talk this year covering development and administration.  My company, Infusion, has been working with Microsoft to deliver quite a few Windows Store (Windows 8 Metro Style) apps.  They have delivered a number of proof of concepts that all have nice touch driven interfaces.  I have been busy with other stuff, so I haven’t had the opportunity to play with this new development model…until now.  My first talk titled, (#SPC025) Bring SharePoint to the Desktop: Building Windows 8 Metro Style Apps with SharePoint is centered around different ways we can leverage SharePoint data in a rich full-screen interface.  This developer-centric talk will show you the basics of building Windows 8 apps and then take advantage of the new SharePoint 2013 APIs to do data binding and notifications.  If you have an interest in Windows 8 and SharePoint, this talk is for you.

My other talk, (#SPC195) PowerShell 3.0 Administration with SharePoint 2013, covers everything from tips and tricks with PowerShell to key new cmdlets you will want to know about.  We’ll talk about installing solution packages, managing upgrades, provisioning the new service applications, and more.  I promise I’ll do my best to make PowerShell an exciting topic.  I know some of you out there love it, so I think it will be a fun talk.

The session list for SPC12 just got announced so be sure and check it out.  I’ll see you all there.  What are you looking forward to?

Follow me on twitter: @coreyroth.

I was digging through some new PowerShell cmdlets for one of my talks coming up at SharePoint Conference 2012 (SPC12), and I stumbled upon the new cmdlet Import-SPEnterpriseSearchPopularQueries.  I found this cmdlet to be interesting since it can be used to easily seed what shows up in the search suggestions on a given site.  I took the example there and did some tweaking and thought I would share my results. 

We first, need to get a reference to the Search Service Application Proxy using Get-SPEnterpriseSearchServiceApplicationProxy.  Sorry, the cmdlets for search a bit wordy so that is what the Tab key is for. :)

$ssap = Get-SPEnterpriseSearchServiceApplicationProxy

Search suggestions are actually specific to the result source and site that hosts the search box.  This means you could have different suggestions depending on which part of the site you are on.  To achieve that, we need to get a reference to the web hosting the search center and ultimately a result source object.  Let’s get the web first.  Change the URL to match your server’s search center.

$searchWeb = Get-SPWeb -Identity http://myserver/search

Now, we will use the Federation Manager to get a result source.  However, we need a Search Object Owner first.  The example on TechNet requires a lot more typing.  I luckily found the cmdlet Get-SPSearchObjectOwner.  It takes a scope (Level) and an SPWeb object.

$owner = Get-SPEnterpriseSearchOwner -Level SPWeb -SPWeb $searchWeb

Unfortunately, I couldn’t find a command to directly get a result source so that means we actually have to go through the API to get a Federation Manager first.

$mgr = new-object Microsoft.Office.Server.Search.Administration.Query.FederationManager -ArgumentList $ssap

Once we have the manager object, we use the GetSourceByName method passing it the name of the result source and $owner.  In this case, we use “Local SharePoint Results" as the result source name.

$source = $mgr.GetSourceByName("Local SharePoint Results", $owner)

As far as the query suggestions themselves, we will need to create a CSV file with the data.  The format is simple: Query Text,Query Count,Click Count,LCID.  For example:

SharePoint Conference,500,300,1033

Setting these values allows you to control the order in which items appear in the query suggestions.  For suggestions to appear in the search box, the click count must be at least 5.  1033 is the LCID value for English.  Here is what my file looks like:

SearchQuerySuggestionsCSV

Now, we run the Import-SPEnterpriseSearchPopularQueries cmdlet.  It needs the SearchApplicationProxy, Filename, and ResultSource parameters which we retrieved with the previous lines of script.

Import-SPEnterpriseSearchPopularQueries -SearchApplicationProxy $ssap -Filename .\suggestions.csv -ResultSource $source -Web $searchWeb

If all commands execute successfully, you should not see anything returned at the command prompt.  Now, you can begin using your suggestions right away.  You do not need to recrawl.  Go to the search center that you specified in your $searchWeb object.  Start typing some of the values from your suggestions and you will see them beneath the search box.

SearchQuerySuggestions

This new PowerShell cmdlet makes it so easy to seed your search suggestions.  I think I will start recommending this on new deployments to really improve the immediate value of search.  Try it out today.

When I first gave the Preview of Search in SharePoint 2013, I mentioned that we could now query search using the Client Object Model.  After enough digging through the documentation, I finally pieced together the steps required to get search results back using this new API.  Today, I will demonstrate how to query from a console application.  To get started, we first need to add referenced to the appropriate assemblies.  These assemblies can be found in the ISAPI folder of the 15 hive.

  • Microsoft.SharePoint.Client.dll
  • Microsoft.SharePoint.Client.Runtime.dll
  • Microsoft.SharePoint.Client.Search.dll

Now in our console application, we need to add the necessary references.

using Microsoft.SharePoint.Client;

using Microsoft.SharePoint.Client.Search;

using Microsoft.SharePoint.Client.Search.Query;

This next step should be familiar if you have used the Client Object Model before in SharePoint 2010.  Start by creating a ClientContext object and pass in the URL to a site.  Put this in a using block.

using (ClientContext clientContext = new ClientContext("http://servername"))

We then need to create a KeywordQuery class to describe the query.  This class is similar to the server side KeywordQuery class but there are some differences.  We pass the ClientContext into the constructor.

KeywordQuery keywordQuery = new KeywordQuery(clientContext);

To set the query use the QueryText property.  In this case, I am doing a search for the keyword “SharePoint”.

keywordQuery.QueryText = "SharePoint";

Unlike the server object model, with the Client OM we have to use another class, SearchExecutor, to send the queries to the search engine.  We pass a ClientContext to it as well:

SearchExecutor searchExecutor = new SearchExecutor(clientContext);

To execute the query, we use the ExecuteQuery method.  It returns a type of ClientResult<ResultTableCollection>

ClientResult<ResultTableCollection> results = searchExecutor.ExecuteQuery(keywordQuery);

However, the query doesn’t actually execute until you call ExecuteQuery() on the ClientContext object.  If you have done a lot of Client OM work before, you might think you need to call Load() first but it is not required.

clientContext.ExecuteQuery();

Assuming no exception occurs, you can now iterate through the results.  The ClientResult<ResultTableCollection> will have a property called Value.  You will want to check the zero index of it to get the search results.  From there, the ResultRows collection has the data of each row.  This object is simply a dictionary object that you can use an indexer with and pass the name of the managed property.  In the example below, I write out the Title, Path, and Modified Date (Write).

foreach (var resultRow in results.Value[0].ResultRows)

{

    Console.WriteLine("{0}: {1} ({2})", resultRow["Title"], resultRow["Path"], resultRow["Write"]);

}

That’s it.  Here is what the entire class looks like together.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

using Microsoft.SharePoint.Client;

using Microsoft.SharePoint.Client.Search;

using Microsoft.SharePoint.Client.Search.Query;

 

namespace SearchClientObjectModelTest

{

    class Program

    {

        static void Main(string[] args)

        {

            using (ClientContext clientContext = new ClientContext("http://sp2010"))

            {

                KeywordQuery keywordQuery = new KeywordQuery(clientContext);

                keywordQuery.QueryText = "SharePoint";

 

                SearchExecutor searchExecutor = new SearchExecutor(clientContext);

 

                ClientResult<ResultTableCollection> results = searchExecutor.ExecuteQuery(keywordQuery);

                clientContext.ExecuteQuery();

 

                foreach (var resultRow in results.Value[0].ResultRows)

                {

                    Console.WriteLine("{0}: {1} ({2})", resultRow["Title"], resultRow["Path"], resultRow["Write"]);

                }

 

                Console.ReadLine();

            }

        }

    }

}

As you can see, you can get started with Search using the Client Object Model with relatively few lines of code.  This certainly beats, constructing that nasty XML file that the Search Web Service takes.

I cross-posted the Visual Studio Solution to code.msdn.microsoft.com.

Follow me on twitter: @coreyroth.

We have a brand new REST based API for interacting with Search in SharePoint 2013 Preview.  Unfortunately, there is not a lot of information out there yet on how to interact with it.  I have pieced together a couple of bits to help get you started.  If you are looking to bring Search into an HTML / JavaScript based application, you’ll be able to get started right away.  The first piece of the puzzle is putting together the right URL to access Search via REST.  To do this, we start with the server name and append /_api/search/query.  Just typing this into the browser will start giving you useful information.  For example:

http://server/_api/search/query

SearchRESTAPIDefault

If you look towards the bottom, you will see the Key SerializedQuery.  This actually shows you the parameters passed into the request.  It also provides you a hint as to what type of parameters you can pass to the REST interface.  The one that might immediately stand out is QueryText.  This is the actual search query.  Think of it as the equivalent of what you type into the search box.  There are a few other parameters that you can customize here as well such as the SummaryLength, MaxSnippetLength. and more.  Let’s try adding QueryText to our URL and passing in a value.

http://server/_api/search/query?querytext=SharePoint

SearchRESTAPIFailedQuery

It turns out the value always has to be enclosed in single quotes (‘) like this:

http://server/_api/search/query?querytext=’SharePoint’

Now, we get some results:

SearchRESTAPIResults

The search results themselves are included in the d:RelevantResults element.  It contains an element d:Table which has   Bare with me as I am going to post the XML for one of the results so that we can inspect it further.

<d:element m:type="SP.SimpleDataRow">

  <d:Cells>

    <d:element m:type="SP.KeyValue">

      <d:Key>Rank</d:Key>

      <d:Value>20.268159866333</d:Value>

      <d:ValueType>Edm.Double</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>DocId</d:Key>

      <d:Value>31</d:Value>

      <d:ValueType>Edm.Int64</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>WorkId</d:Key>

      <d:Value>31</d:Value>

      <d:ValueType>Edm.Int64</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Title</d:Key>

      <d:Value>Getting the most out of SharePoint Search</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Author</d:Key>

      <d:Value>Corey Roth;SharePoint Setup</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Size</d:Key>

      <d:Value>2425342</d:Value>

      <d:ValueType>Edm.Int64</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Path</d:Key>

      <d:Value>http://sp2010/Shared Documents/Getting the most out of SharePoint Search - SharePoint Saturday Denver.pptx</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Description</d:Key>

      <d:Value>

        Template: Sam Moore; Silver Fox Productions, Inc.&#xD;

        Formatting:&#xD;

        Event Date: October 3-6th, 2011&#xD;

        Event Location: Anaheim, CA&#xD;

        Audience Type: Internal/External

      </d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Write</d:Key>

      <d:Value>2011-11-10T00:00:00.0000000</d:Value>

      <d:ValueType>Edm.DateTime</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>CollapsingStatus</d:Key>

      <d:Value>0</d:Value>

      <d:ValueType>Edm.Int64</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>HitHighlightedSummary</d:Key>

      <d:Value xml:space="preserve">Passed all &lt;c0&gt;SharePoint&lt;/c0&gt; 2010 certification exams &lt;ddd/&gt; Introduce Search in &lt;c0&gt;SharePoint&lt;/c0&gt; Online &lt;ddd/&gt; The talk will be slides with quite a few demos of &lt;c0&gt;SharePoint&lt;/c0&gt; Online features &lt;ddd/&gt; </d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>HitHighlightedProperties</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>contentclass</d:Key>

      <d:Value>STS_ListItem_DocumentLibrary</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>PictureThumbnailURL</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ServerRedirectedURL</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ServerRedirectedEmbedURL</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ServerRedirectedPreviewURL</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>FileExtension</d:Key>

      <d:Value>pptx</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ContentTypeId</d:Key>

      <d:Value>0x010100B1CF83A7F86DFC468C975FFF33126DFD</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ParentLink</d:Key>

      <d:Value>http://sp2010/Shared Documents/Forms/AllItems.aspx</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ViewsLifeTime</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ViewsRecent</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>SectionNames</d:Key>

      <d:Value xml:space="preserve">Getting the most out of SharePoint Search&#xD;

;Getting the most out of SharePoint Search&#xD;

;Corey Roth&#xD;

About me&#xD;

;Key Theme&#xD;

;SharePoint is not a…&#xD;

;SharePoint is a…&#xD;

;Challenges with Search&#xD;

;Agenda&#xD;

;Key Takeaways&#xD;

;You have a choice…&#xD;

;What can search index?&#xD;

;Search in SharePoint&#xD;

;Components of Search&#xD;

;Finding things easier…&#xD;

;Improve search with queries&#xD;

;Built-in Managed Properties&#xD;

;Segmenting results with Scopes&#xD;

;Querying Search and Scopes&#xD;

;Provide more search options&#xD;

;Many options for displaying scopes&#xD;

</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>SectionIndexes</d:Key>

      <d:Value>1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>SiteLogo</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>SiteDescription</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>deeplinks</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>importance</d:Key>

      <d:Value>0</d:Value>

      <d:ValueType>Edm.Int64</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>SiteName</d:Key>

      <d:Value>http://sp2010</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>IsDocument</d:Key>

      <d:Value>true</d:Value>

      <d:ValueType>Edm.Boolean</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>LastModifiedTime</d:Key>

      <d:Value>2011-11-10T00:00:00.0000000</d:Value>

      <d:ValueType>Edm.DateTime</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>FileType</d:Key>

      <d:Value>pptx</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>IsContainer</d:Key>

      <d:Value>false</d:Value>

      <d:ValueType>Edm.Boolean</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>WebTemplate</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>SecondaryFileExtension</d:Key>

      <d:Value>pptx</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>OriginalPath</d:Key>

      <d:Value>http://sp2010/Shared Documents/Getting the most out of SharePoint Search - SharePoint Saturday Denver.pptx</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>DisplayAuthor</d:Key>

      <d:Value>Corey Roth;SharePoint Setup</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Created</d:Key>

      <d:Value>2012-07-26T23:21:29.0000000</d:Value>

      <d:ValueType>Edm.DateTime</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>PeopleInMedia</d:Key>

      <d:Value></d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>MediaDuration</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>PictureWidth</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>PictureHeight</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>DefaultEncodingURL</d:Key>

      <d:Value>http://sp2010/Shared%20Documents/Getting%20the%20most%20out%20of%20SharePoint%20Search%20-%20SharePoint%20Saturday%20Denver.pptx</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ExternalMediaURL</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>UserEncodingURL</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Community_MembersCount</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Community_RepliesCount</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Community_TopicsCount</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ReplyCount</d:Key>

      <d:Value>0</d:Value>

      <d:ValueType>Edm.Int64</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>LikesCount</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Discussion_BestAnswerID</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Discussion_Category</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Discussion_Post</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Discussion_LikesCount</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ListItemID</d:Key>

      <d:Value>6</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>FullPostBody</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>PostAuthor</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>RootPostOwnerID</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>RootPostID</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>AttachmentType</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>AttachmentURI</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>MicroBlogType</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ModifiedBy</d:Key>

      <d:Value>

        Corey Roth

 

        SharePoint Setup

      </d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>RootPostUniqueID</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>Tags</d:Key>

      <d:Value></d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ImageDateCreated</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>PictureURL</d:Key>

      <d:Value m:null="true" />

      <d:ValueType>Null</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ResultTypeIdList</d:Key>

      <d:Value>2;6</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>PartitionId</d:Key>

      <d:Value>0c37852b-34d0-418e-91c6-2ac25af4be5b</d:Value>

      <d:ValueType>Edm.Guid</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>UrlZone</d:Key>

      <d:Value>0</d:Value>

      <d:ValueType>Edm.Int32</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>AAMEnabledManagedProperties</d:Key>

      <d:Value>HierarchyUrl;OrgParentUrls;OrgUrls;OriginalPath;Path;recommendedfor;SitePath</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>ResultTypeId</d:Key>

      <d:Value>2</d:Value>

      <d:ValueType>Edm.Int32</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>RenderTemplateId</d:Key>

      <d:Value>~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_PowerPoint.js</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

    <d:element m:type="SP.KeyValue">

      <d:Key>piSearchResultId</d:Key>

      <d:Value>1_1</d:Value>

      <d:ValueType>Edm.String</d:ValueType>

    </d:element>

  </d:Cells>

</d:element>

As you can see, we now get a ton of information back from Search for a given search result.  Let me point out some of the more interesting values.  We have the usual values such as Title, Path, Author, Write (Modified Date), and HitHighlightedSummary.  However, we also get a ton of new information.  For images, you will get a PictureThumbnailUrl to allow you to easily show a thumbnail.  This particular result is a PowerPoint and search understands the individual sections inside it now which you will see in SectionNamesSiteName provides the site hosting the item.  Tags will provide any use of the Enterprise Keywords field.  You also get a heap of social information about the item as well such as how many likes.  Lastly, the RenderTemplateId tells you which template the result source is using to display it on the search results page.  This is just one example, but you can see we get a lot of useful information about the search.

Looking at the XML in the browser is a great way to get familiar with what the API has to offer.  When you are ready to start developing, it is very easy to take advantage of the REST API using JavaScript.  You can do this with the $.ajax() method in jQuery and pass in the URL you used in the browser.  You want to use the GET method and pass in a header telling it you want the results back as json.  They have a good example of how this works on code.msdn.microsoft.com.  Specifically, take a look at App.js in the example to see the code in action.  It’s pretty simple.

If you want to take advantage of the REST API from C# or another .NET language, that is another story though.  I haven’t been able to add a service reference for the REST API.  All of the server side code examples I have seen call the REST API using HttpWebRequest which requires no less than 60 lines of code or so.  I am hoping there is a better way but I haven’t seen one yet.  If you have had better luck be sure and let me know.