January 2012 - Posts

SharePoint URLs can be quite long.  When you paste a link to a document in an E-mail they can prove to be quite long.  The community has developed a number of solutions for SharePoint URL shorteners.  However, I thought I would share a quick solution that you can take advantage of as an end user without requiring any SharePoint customizations.  I regularly use SharePoint Workspace to work on my most common projects.  If you haven’t worked with it before, see this post for more on how to get started.  Whenever, you need to share a link to a document, just right click on the document and use the Copy as Link menu item.

SharePointWorkspaceCopyAsLink

You can then paste the link into Outlook, a Word document, or wherever.  When you do, it creates a nice link using the filename of the document instead of the full URL of the document.

SharePointWorkspaceLink

It’s that simple.  Sometimes, you may get an error when using the Copy as Link feature but when that happens it still copies the link to your clipboard.

Visual Studio 11 adds a new feature that makes working with Silverlight in SharePoint 2010 a bit easier.  The new Silverlight Web Part feature automates deploying your Silverlight applications to SharePoint and can really save you a bit of time.  We took a look at how the Visual Web Part works in VS11 a while back.  Now, let’s see what happens when we use Silverlight. 

To work with Silverlight,you can either create a new project or simply add a new item to an existing project.  I’ll start by creating a new project by choosing the item SharePoint 2010 Silverlight Web Part.  Remember the number of project types has been reduced in VS11.

VS11DPNewSharePointSilverlightProject

After you provide the usual SharePoint specific information, a new screen will prompt you for information on your Silverlight application.  You can use an existing application or let it create a new project for you.

VS11DPNewSharePointSilverlightWebPart

You have a choice of Silverlight version 4.0 or 5.0.  Once you finish, you’ll have two new projects to work with.  The designer opens up and then we’ll just create a simple Silverlight application.

VS11DPSilverlightApplication

Now, let’s take a look at the files.  They prove to be a lot simpler than you might think.

VS11DPSilverlightSolutionExplorer

If we click on the web part itself, we actually see the contents of the .webpart file.  Taking a quick look at it, reveals its simplicity.

<?xml version="1.0" encoding="utf-8"?>

<webParts>

  <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">

    <metaData>

      <type name="Microsoft.SharePoint.WebPartPages.SilverlightWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL" />

      <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>

    </metaData>

    <data>

      <properties>

        <property name="Title" type="string">SilverlightWebPartProject1 - SilverlightWebPart1</property>

        <property name="Description" type="string">My Silverlight Web Part</property>

        <property name="Height" type="unit">300px</property>

        <property name="Width" type="unit">400px</property>

        <property name="Url" type="string">/SiteAssets/SilverlightWebPartProject1/SilverlightWebPart1/SilverlightProject1.xap</property>

      </properties>

    </data>

  </webPart>

</webParts>

It simply has a reference to the existing SilverlightWebPart included in SharePoint 2010.  It sets a few properties such as Title, Description, Height, Width, and Url.  Here you will notice that it’s actually copying the .xap file from your Silverlight project into the SiteAssets library.  Note, that this is the only place to set the dimensions of your web part.

<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/" >

  <Module Name="SilverlightWebPart1" List="113" Url="_catalogs/wp">

    <File Path="SilverlightWebPart1\SilverlightWebPart1.webpart" Url="SilverlightWebPartProject1_SilverlightWebPart1.webpart" Type="GhostableInLibrary" >

      <Property Name="Group" Value="Custom" />

    </File>

  </Module>

  <Module Name="SilverlightWebPart1">

    <File Path="SilverlightWebPart1\SilverlightProject1.xap" Url="SiteAssets/SilverlightWebPartProject1/SilverlightWebPart1/SilverlightProject1.xap" />

  </Module>

</Elements>

If we take a look at the Elements.xml file, we see that it deploys both the .webpart file and the .xap file using a Module element.

When you are ready to deploy just use the Deploy command in Visual Studio.  It will build the Silverlight application, the .wsp file and send it to SharePoint.  You no longer have to manually upload the .xap file (or add it manually to your package).  Now, we can just add the web part to a page from the Insert ribbon.

VS11DPAddSilverlightWebPart

Then you’ll have your Silverlight application on your page.  Don’t be jealous of how great this one looks. :)

VS11DPSilverlightWebPart

What about SharePoint Online?  Does it work there too?  Indeed it does.  Just use the Publish feature I talked about earlier to deploy that solution to the cloud.  One issue I did notice is that the path configured in the SilverlightWebPart is absolute.  If you publish into a site collection not on the root, you’ll need to modify the path.  I need to look at this one more since it might be based off of the local SharePoint site URL that you specified originally.  Still it’s nice to know that it works.  I tried it with an E3 account and I’m pretty sure it will work with P accounts as well.

I often refer to my Handy Keywords in SharePoint Search because it forms the building blocks you need to become a rock star at writing SharePoint keyword queries.   Today, I want to expand upon that post on how you can use search to return a list of sites or site collections.  This is useful when you want to quickly inspect a SharePoint farm using the Search Center.  The secret behind returning sites with Search is use of the contentclass managed property.  You just have to know what value to specify.  To return a list of all sites in the search index, we specify a value of STS_Web (remember our translation guide).  Here is what it looks like.

contentclass:"STS_Web"

SPOSearchSites

This works pretty well.  However, if you inspect the results on your own server, you might quickly notice one thing missing.  The root web of all the site collections is not present in the search results.  To get the site collections, we specify STS_Site instead.

contentclass:"STS_Site"

SPOSearchSiteCollections

Notice, I now have all of the site collections on my particular tenant.  If you want the results combined, you simply combine the queries.

contentclass:"STS_Site" contentclass:"STS_Web"

SPOSearchSitesAll

Now you might be thinking this is great, but you don’t want every site and site collection on the farm.  You want to restrict it to a particular web application.  That’s actually pretty easy, just refer back to the handy keywords post and use the Site managed property.  In my case, I’ll restrict the URL to my main web application.

contentclass:"STS_Site" contentclass:"STS_Web" site:https://dotnetmafia.sharepoint.com

SPSitesAllRestricted

There are lots of ways to get lists of sites in SharePoint, but I find this one works well since it doesn’t require a line of code for you to try.  Of course, as a developer, you can make use of this with the KeywordQuery class inside your own application.  This works with SharePoint on-premises as well as SharePoint Online.  All screenshots were from my personal SPO site.

I recently published my first post about SharePoint development with Visual Studio 11 and I mentioned that there were some changes in how the Visual Web Part worked.  If you are familiar with the Visual Web Part in Visual Studio 2010, you know it really is just a glorified user control and it doesn’t work in the sandbox.  Luckily, the community stepped up and provided some alternatives that do work.  Visual Studio 11 now provides a Visual Web Part that works in the sandbox out of the box.  Since I am always curious about how things work, I decided to take a deeper look to see just how this web part is implemented now. 

Let’s first take a look at the files that we get when we add a Visual Web Part to the project.

VS11DPVisualWebPartSolutionExplorer

There are actually a few less files that we had in Visual Studio 2010.  We’ll see why here shortly.  What we get are the following

  • Elements.xml – Used to deploy the .webpart file via module element
  • A .ascx file – The actual user control with the design surface
  • A .ascx.cs file – The code behind for the user control
  • A .ascx.g.cs file – This file is generated by the designer.  We’ll talk about it more
  • A .webpart file – The file that goes into the Web Part gallery that has the assembly path to the web part

If we look at the .ascx.cs file, we’ll see our first difference. 

using System;

using System.ComponentModel;

using System.Web.UI.WebControls.WebParts;

 

namespace SharePointProject1.HelloWorldWebPart

{

    [ToolboxItemAttribute(false)]

    public partial class HelloWorldWebPart : WebPart

    {

        protected override void OnInit(EventArgs e)

        {

            base.OnInit(e);

            InitializeControl();

        }

 

        protected void Page_Load(object sender, EventArgs e)

        {

        }

    }

}

You’ll notice that this file inherits from WebPart now instead of UserControl.  At this point, you might be wonder how does all of this work.  Well, the magic is in the designer and what ends up in the .ascx.g.cs file.  Let’s take a look at it when it’s first created.

//------------------------------------------------------------------------------

// <auto-generated>

//     This code was generated by a tool.

//     Runtime Version:2.0.50727.5448

//

//     Changes to this file may cause incorrect behavior and will be lost if

//     the code is regenerated.

// </auto-generated>

//------------------------------------------------------------------------------

 

namespace SharePointProject1.HelloWorldWebPart {

    using System.Web;

    using System.Text.RegularExpressions;

    using Microsoft.SharePoint.WebPartPages;

    using Microsoft.SharePoint.WebControls;

    using System.Web.Security;

    using Microsoft.SharePoint.Utilities;

    using System.Web.UI;

    using System;

    using System.Web.UI.WebControls;

    using System.Collections.Specialized;

    using Microsoft.SharePoint;

    using System.Collections;

    using System.Web.Profile;

    using System.Text;

    using System.Web.Caching;

    using System.Configuration;

    using System.Web.UI.WebControls.WebParts;

    using System.Web.SessionState;

    using System.Web.UI.HtmlControls;

 

 

    public partial class HelloWorldWebPart {

 

        public static implicit operator global::System.Web.UI.TemplateControl(HelloWorldWebPart target)

        {

            return target == null ? null : target.TemplateControl;

        }

 

        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]

        private void @__BuildControlTree(global::SharePointProject1.HelloWorldWebPart.HelloWorldWebPart @__ctrl) {

        }

 

        private void InitializeControl() {

            this.@__BuildControlTree(this);

            this.Load += new global::System.EventHandler(this.Page_Load);

        }

 

        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]

        protected virtual object Eval(string expression) {

            return global::System.Web.UI.DataBinder.Eval(this.Page.GetDataItem(), expression);

        }

 

        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]

        protected virtual string Eval(string expression, string format) {

            return global::System.Web.UI.DataBinder.Eval(this.Page.GetDataItem(), expression, format);

        }

    }

}

It may not make a lot of sense at this point, but when you start adding controls, it makes more sense.  I added a label, textbox, and button control to the design surface.

VS11DPVisualWebPartDesigner

This looks like a typical user control that you are confortable working with.  Now let’s take a look at what the .ascx.g.cs file has now.  I’ll just include the parts that changed.

[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]

private global::System.Web.UI.WebControls.Label @__BuildControlLabel1() {

    global::System.Web.UI.WebControls.Label @__ctrl;

    @__ctrl = new global::System.Web.UI.WebControls.Label();

    this.Label1 = @__ctrl;

    @__ctrl.ApplyStyleSheetSkin(this.Page);

    @__ctrl.ID = "Label1";

    @__ctrl.Text = "Label";

    return @__ctrl;

}

 

[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]

private global::System.Web.UI.WebControls.TextBox @__BuildControlTextBox1() {

    global::System.Web.UI.WebControls.TextBox @__ctrl;

    @__ctrl = new global::System.Web.UI.WebControls.TextBox();

    this.TextBox1 = @__ctrl;

    @__ctrl.ApplyStyleSheetSkin(this.Page);

    @__ctrl.ID = "TextBox1";

    return @__ctrl;

}

 

[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]

private global::System.Web.UI.WebControls.Button @__BuildControlButton1() {

    global::System.Web.UI.WebControls.Button @__ctrl;

    @__ctrl = new global::System.Web.UI.WebControls.Button();

    this.Button1 = @__ctrl;

    @__ctrl.ApplyStyleSheetSkin(this.Page);

    @__ctrl.ID = "Button1";

    @__ctrl.Text = "Button";

    return @__ctrl;

}

 

[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]

private void @__BuildControlTree(global::SharePointProject1.HelloWorldWebPart.HelloWorldWebPart @__ctrl) {

    System.Web.UI.IParserAccessor @__parser = ((System.Web.UI.IParserAccessor)(@__ctrl));

    @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n<div>\r\n    "));

    global::System.Web.UI.WebControls.Label @__ctrl1;

    @__ctrl1 = this.@__BuildControlLabel1();

    @__parser.AddParsedSubObject(@__ctrl1);

    @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n    "));

    global::System.Web.UI.WebControls.TextBox @__ctrl2;

    @__ctrl2 = this.@__BuildControlTextBox1();

    @__parser.AddParsedSubObject(@__ctrl2);

    global::System.Web.UI.WebControls.Button @__ctrl3;

    @__ctrl3 = this.@__BuildControlButton1();

    @__parser.AddParsedSubObject(@__ctrl3);

    @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n</div>\r\n"));

}

The designer creates methods for each ASP.NET control you drag onto the page and then the @__BuiltControlTree method calls those methods to effectively add those controls to the page.  The HTML div elements that I added to the page simply get included as a LiteralControl.  Needless to say you don’t want to mess with this file.  I have to give props to the Visual Studio and SharePoint teams.  I am sure this was a lot of work to implement.  :)  Give it a try if you want.  It seems to work well and the best part is what I have tried so far works with SharePoint Online.

If you haven’t checked out Visual Studio 11 yet, head over to the developer site where you can get the download link and find out everything that’s new.

So I’ve been living under a rock again and I had never gotten around to checking what’s new in Visual Studio 11.  The Developer Preview has been around a while and I wanted to check it out today and was surprised to see some new SharePoint development features that I am really excited about.  If you have been following me, you know I have been doing some work with Office 365 and SharePoint Online, so when I read about the new Publish feature in Visual Studio 11, I had to check it out.  Let’s start by creating a new project with a simple web part.  We’ll look and what’s new and see how exactly we can publish to SharePoint Online.

Open Visual Studio 11 and go to the New Project menu.  If you are familiar with this menu in Visual Studio 2010, you will quickly notice some differences.

VS11DPNewSharePointProject

First, you will notice you have a lot less choices.  I really like this change.  I always found it confusing that there was many project types that really just equated to a SharePoint Project Item that you would create in any project using the New Item menu.  I always used the blank SharePoint project and we now refer to this simply as a SharePoint 2010 Project.  Be sure and change the framework to .NET Framework 3.5 as it default to .NET Framework 4.5 by default.  One other change you might notice is that there are no longer any SharePoint 2007 projects available.

Create a SharePoint 2010 Project and then be sure and check Sandboxed Solution since we are going to the cloud.  Go ahead and create a new Visual Web Part next.  Now you might be thinking, that you can’t do Visual Web Parts in sandboxed solutions.  In the past, we had to rely on tools from the community to make this happen.  Now Visual Studio 11 supports Visual Web Parts out-of-the-box.  We’ll talk more about these in my next post.  Drag a label or whatever ASP.NET controls you want onto the design surface and create your “Hello, World!” text.  When you are done, click Build.  Don’t bother deploying it though.

Now we want to publish this solution to SharePoint Online.  Visual Studio 11 actually makes it quite easy.  Right click on the project and click Publish.  This brings up a new dialog prompting you for the URL to your site.  You can specify another SharePoint 2010 server or in our case we’ll specify my URL to a site collection in SPO.

VS11DPPublishSolution

Once you click the Publish button, it will take a few seconds to connect and finally it will prompt you for authentication.

VS11PublishO365Signin

Enter your credentials and the solution will publish soon.  When it is done, you will be taken to the Solutions gallery.  At this point, you need to select the solution and click the Activate button to make your solution available.

VS11DPO365SolutionGallery 

At this point, you can edit any page and find your web part in the list.  I just added it to the home page of the site as you can see in the screenshot below.

VS11DO365SandboxedWebPart

I’ve talked about how to deploy solutions to SharePoint Online in the past and this makes things much easier.  This will definitely reduce development time.  We still have to throw our solution “over the fence”, but at least it’s somewhat automated now.  I can only hope for debugging in the cloud some day. :)

One thing to note is that you still have to do the development on a machine that has SharePoint installed.  I even tried to trick it, but it wouldn’t cooperate. 

Now, you might be thinking this is great and wondering if you should switch to Visual Studio 11 for SharePoint Online development.  At this point, I don’t see any huge risk in doing that, but don’t blame me if things blow up. :)  Make use of source control and backups and you should be able to correct anything that VS11 manages to break.  When you are using source control, I see the worst that could happen is that you might have to go back a version or two in source control.  For the extreme pessimist, I am sure worse could happen, but you always take that risk with pre-release software.

If you haven’t checked out Visual Studio 11 yet, head over to the developer site where you can get the download link and find out everything that’s new.

Ever wanted to see what exactly is in your SharePoint search index with a simple query?  Sure, you can take a look at the crawl log, but you can’t see that in SharePoint Online.  With SharePoint 2010, you can use queries using the ContentSource keyword to return everything in that content source (i.e.: Local SharePoint sites).  However, you may want to see the entire index.  Well that’s actually pretty easy.  Just use type % in the search box and submit your query.  It will return everything there is. 

SearchResultsPercentFAST

This is a great way to see what is in your search index.  It can also help you find things that maybe you didn’t want indexed.  It even works with SharePoint Online as well.

SearchResultsPercentSPO

What about people search?  It works there too with SharePoint Online.

PeopleSearchResultsPercentSPO

However, this doesn’t work in FAST Search for SharePoint (which is just SharePoint Search when it comes to people) for me.  Even still, % is a useful operator that you can use to help troubleshoot issues with search.

UPDATE: Erich Stehr pointed out that % does not work on regular SharePoint Enterprise Search.  He is correct.  What is odd is that it does work in SharePoint Online.  That will make you think about things.  As an alternative, you can issue the query Size>=0 (no spaces) to return the entire index as well.

At my Search talk at SPC11, I demoed how to build a Silverlight application that could query search in SharePoint Online.  I also built a separate application that could query people search, but I haven’t posted on it yet until today.  To query people search, we have to know a few things about how SharePoint operates.  It all starts with understanding the scopes involved.  If you take a look at your Search Scopes link in your site collection settings, you’ll see a similar list to the one below.

SharePointOnlineSearchScopes

What’s funny here is that SPO actually returns item counts for the entire (non-partitioned index).  This tells me that there are 205,000 items and 96,000 people on my particular Office 365 SharePoint host. 

Ultimately, querying people search is just a matter of executing a query against the scope People, but there are a few catches.  In SharePoint 2007, you could actually execute the query Scope:”People” on a results.aspx with a CoreResultsWebPart and you would actually get results.  It wouldn’t display pictures or additional user information such as department or phone number, but it would work.  With the introduction of federated search in SharePoint 2010, people search now gets executed by it’s own federated location named LocalPeopleSearchIndex (see my post on the QueryManager class for more information).  This means that a regular CoreResultsWebPart will not return results for Scope:”People” no matter what you do. 

SharePointOnlinePeopleSearchNoResults

However, a PeopleCoreResultsWebPart will.

SPOPeopleCoreResults

Issuing the query Scope:”People” will return every user in the user profile store.  Including service accounts like you see above.  The fact that I couldn’t issue a people search query to the regular CoreResultsWebPart actually threw me off for quite some time.  It just didn’t make sense to me what was going on behind the scenes.  It didn’t become ultimately clear, until I tried issuing the query to Search.asmx.  The Scope:”People” query works just fine when calling the web service.  Today you will learn how to query people search using the web service.  I’m going to use the exact same application I have been using with my other search demos, we’ll just tweak the input a little bit.

For today’s example, I am going to build off of the Silverlight 4 application I used at SPC.  I’m using Silverlight, but you could just as well write a console application or call this web service from some other ASP.NET application.  We still want to start by creating a service reference to /_vti_bin/search.asmx. We then create an instance of the web service so that we can use it.  We also bind an event handling method to handle the results of the web service call.

QueryServiceSoapClient queryService = new QueryServiceSoapClient();

queryService.QueryExCompleted += new EventHandler<QueryExCompletedEventArgs>(QueryService_QueryExCompleted);

Once we have a reference to the web service, it’s just a matter of constructing the input XML document and sending it to the web service.  For SharePoint Online and SharePoint 2010, we actually don’t have to change any of the XML at all. We just need to change the query. That means our input will look like the following.  Note, we’re using a type of STRING (even if using FAST Search for SharePoint).

<QueryPacket xmlns="urn:Microsoft.Search.Query" Revision="1000">

  <Query domain="QDomain">

    <SupportedFormats>

      <Format>urn:Microsoft.Search.Response.Document.Document</Format>

    </SupportedFormats>

    <Context>

      <QueryText language="en-US" type="STRING">Scope:"People"</QueryText>

    </Context>

  </Query>

</QueryPacket>

If we are using FAST Search for SharePoint, we need to add to a ResultProvider element inside the Query element.  Remember, People Search is handled by the SharePoint 2010 search engine in FAST Search for SharePoint.

<ResultProvider>SharePointSearch</ResultProvider>

Just like before, I assemble this XML string using a StringBuilder.  I allow the user to type in a query and I just automatically append Scope:”People” to the query ensuring we only get people results.

StringBuilder queryXml = new StringBuilder();

 

queryXml.Append("<QueryPacket xmlns=\"urn:Microsoft.Search.Query\" Revision=\"1000\">");

queryXml.Append("<Query domain=\"QDomain\">");

queryXml.Append("<SupportedFormats>");

queryXml.Append("<Format>");

queryXml.Append("urn:Microsoft.Search.Response.Document.Document");

queryXml.Append("</Format>");

queryXml.Append("</SupportedFormats>");

queryXml.Append("<Context>");

queryXml.Append("<QueryText language=\"en-US\" type=\"STRING\">");

queryXml.AppendFormat("{0} Scope:\"People\"", SearchTextBox.Text);

queryXml.Append("</QueryText>");

queryXml.Append("</Context>");

queryXml.Append("</Query>");

queryXml.Append("</QueryPacket>");

 

queryService.QueryExAsync(queryXml.ToString());

We’ll then bind the resulting XML to a textbox so that we can look at the results.

ResultsTextBox.Text = e.Result.Nodes[1].ToString();

That’s all that is involved in this first round of code.  Compile the code and upload the Silverlight application to a document library and use the Silverlight web part just like before.  If you want more details on how the above code works, be sure and check out the original Search with Silverlight 4 post.   Let’s take a look at the results.  Here’s the application running.

SPOPeopleSearchSilverlight1

I issues a query and I got results.  Let’s look at the XML in the results a bit more though.

<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">

  <Results xmlns="">

    <RelevantResults diffgr:id="RelevantResults1" msdata:rowOrder="0">

      <WorkId>72787</WorkId>

      <Rank>100000000</Rank>

      <Title>Craig Johnson</Title>

      <Size>0</Size>

      <Path>https://dotnetmafia-my.sharepoint.com/Person.aspx?accountname=i%3A0%23.f|membership|craig.johnson%40dotnetmafia.onmicrosoft.com</Path>

      <Write>2011-09-09T18:20:05-07:00</Write>

      <SiteName>https://dotnetmafia-my.sharepoint.com</SiteName>

      <CollapsingStatus>0</CollapsingStatus>

      <HitHighlightedSummary />

      <HitHighlightedProperties>&lt;HHTitle&gt;Craig Johnson&lt;/HHTitle&gt;&lt;HHUrl&gt;https://dotnetmafia-my.sharepoint.com/Person.aspx?accountname=i%3A0%23.f|membership|craig.johnson%40dotnetmafia.onmicrosoft.com&lt;/HHUrl&gt;</HitHighlightedProperties>

      <ContentClass>urn:content-class:SPSPeople</ContentClass>

      <IsDocument>false</IsDocument>

      <PictureThumbnailURL>https://dotnetmafia-my.sharepoint.com/User Photos/Profile Pictures/i_0_.f_membership_craig.johnson@dotnetmafia.onmicrosoft.com_MThumb.jpg</PictureThumbnailURL>

    </RelevantResults>

We have the user’s name in the Title field and we have some links to a picture and the user’s profile.  For the most part though, these fields aren’t entirely useful.  That’s because SharePoint treats this result as a regular document result instead of a person.  If we want useful information about the user, we have to ask for that information in our original query.  Specifically, we need to specify the names of the managed properties that we want returned (i.e.: JobTitle and Department).  How do we know what the names of those properties are?  In SharePoint 2010, we can just go look in the search service application.  However, we don’t have that option in SharePoint Online.  There’s another way though.  Go back to your PeopleResults.aspx page in your Search Center and edit it.  Then, you need to modify the PeopleCoreResultsWebPart.  Expand Display Properties and then uncheck Use Location Visualization.  The contents of the XML in Fetched Properties has the answer. 

SPOPeopleCoreResultsDisplayProperties

Here is what the XML looks like.

<Columns>

  <Column Name="WorkId"/>

  <Column Name="UserProfile_GUID"/>

  <Column Name="AccountName"/>

  <Column Name="PreferredName" HitHighLight="true"/>

  <Column Name="YomiDisplayName" HitHighLight="true"/>

  <Column Name="JobTitle" HitHighLight="true"/>

  <Column Name="Department" HitHighLight="true"/>

  <Column Name="WorkPhone" HitHighLight="true"/>

  <Column Name="OfficeNumber" HitHighLight="true"/>

  <Column Name="PictureURL"/>

  <Column Name="HierarchyUrl"/>

  <Column Name="WorkEmail" HitHighLight="true"/>

  <Column Name="Path"/>

  <Column Name="HitHighlightedSummary"/>

  <Column Name="HitHighlightedProperties"/>

  <Column Name="Responsibility" HitHighLight="true"/>

  <Column Name="Skills" HitHighLight="true"/>

  <Column Name="SipAddress" HitHighLight="true"/>

  <Column Name="Schools" HitHighLight="true"/>

  <Column Name="PastProjects" HitHighLight="true"/>

  <Column Name="Interests" HitHighLight="true"/>

  <Column Name="OrgNames" HitHighLight="true"/>

  <Column Name="OrgUrls"/>

  <Column Name="OrgParentNames" HitHighLight="true"/>

  <Column Name="OrgParentUrls"/>

  <Column Name="Memberships" HitHighLight="true"/>

  <Column Name="AboutMe" HitHighLight="true"/>

  <Column Name="BaseOfficeLocation" HitHighLight="true"/>

  <Column Name="ServiceApplicationID"/>

  <Column Name="SocialDistance"/>

</Columns>

This gives you quite a few choices to display in your results.  The column names are pretty self explanatory.  Now, we just have modify our input XML to specify which managed properties we want.  Do you remember how to specify managed properties with the Search web service?  If not, we start by adding a Properties element inside the Query element.  We then add a Property element for each managed property.  One thing to remember is that the managed properties must be specified in lower case.  You will get a NotFound exception if they are not.  Here is an example:

<Properties>

  <Property name="accountname" />

  <Property name="preferredname" />

  <Property name="jobtitle" />

  <Property name="department" />

  <Property name="workphone" />

  <Property name="officenumber" />

  <Property name="pictureurl" />

  <Property name="workemail" />

</Properties>

Remember, once you specify any column, you must specify every column you want.  The default columns will no longer be returned.  When we recompile, upload the new application, and execute a query again, we now get much better results.

<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">

  <Results xmlns="">

    <RelevantResults diffgr:id="RelevantResults1" msdata:rowOrder="0">

      <accountname>i:0#.f|membership|craig.johnson@dotnetmafia.onmicrosoft.com</accountname>

      <preferredname>Craig Johnson</preferredname>

      <jobtitle>Accountant</jobtitle>

      <department>Accounts Receivable</department>

      <workphone>123-555-1215</workphone>

      <officenumber>123455</officenumber>

      <pictureurl>https://dotnetmafia-my.sharepoint.com/User Photos/Profile Pictures/i_0_.f_membership_craig.johnson@dotnetmafia.onmicrosoft.com_MThumb.jpg</pictureurl>

      <workemail>craig.johnson@dotnetmafia.onmicrosoft.com</workemail>

    </RelevantResults>

You can query with these same managed properties as well.  For example, I could use the department managed property to see who is in Accounting with the following query.

department:”accounting”

SPOPeopleSearchSilverlightDepartment

Maybe, you want to look up who the CEO of the company is.  To do that use the jobtitle managed property.  Resist the urge to capitalize the words in the managed property.  They must be in lower case.  Note: that the title managed property is reserved for personal titles such as Jr., Sr. etc.

jobtitle:”CEO”

SPOPeopleSearchSilverlightJobTitle

Now, that we can query with all of these properties, we can make a nice advanced people search application.  In my demo at SPC11, I used the Telerik RadGridView control to display the user information along with the picture from the user profile.  Here’s a screenshot of what the application looked like.

SPOPeopleSearchApplication

You can use the same techniques that I detailed in the Advanced Search with Silverlight 4 post to build a people search application like the one above.  This code will work on-premises (SharePoint 2010 or FAST Search for SharePoint) or in the cloud with SharePoint Online.  I’ve confirmed this works with both the P1 and E3 SKUs of Office 365.