Lately I’ve been trying to blend three different technologies, namingly Sharepoint 2010, SSRS and Silverlight 4 into one application. The goal of the project was to display existing reports of SSRS plus some features of Sharepoint in a Silverlight application that runs inside Sharepoint or as an out of browser application. You may say that SSRS and Sharepoint already work together, so why add Silverlight to the equation? The thing is that customer was so happy with previous Silverlight applications we demoed, that they don’t like to working with old, flat html websites anymore and need a richer application to work with.

Just to see the possibility and getting to know the problems along the way, let’s just focus on integrating a Silverlight application with Sharepoint 2010 for now.

It turns out, Sharepoint already has some webservices at our disposal. It provides services to do:

  • Administration jobs
  • Authentication
  • Diagnostics
  • Queries against lists
  • Managing document workspaces
  • Searching
  • Working with Forms, WebParts

So chances are there is a Sharepoint webservice to do the thing you want.

Other than webservices, in Sharepoint 2010, there is a Managed Client Object Model that is also usable in Silverlight. You can use this library to query SP but it still uses a WCF Service (Client.svc) behind the scene. The good thing about Client object model is that you can use LINQ queries to load Sharepoint related data instead of calling an RPC WebService, but it is just different means toward the same goal.

To show you how this works, let’s create a Silverlight application that searches Sharepoint and displays the result inside our SL app. To do this, create a Silverlight 4 application and add a service reference to Sharepoint search webservice located at http://sharepointmachine/_vti_bin/Search.asmx and let the VS create proxy objects for you.

There are two query methods available on the service, we’ll use QueryAsync method that returns a raw xml and not QueryAsyncEx which returns a DataSet (there’s no DataSet in Silverlight version of CLR anyway). We also use the same Silverlight Webservice calling patterns when calling Sharepoint webservices (e.g. calling the Async method and waiting for Completed event). Here’s how:

1
2
3
4
5
6
7
8
private void SearchButtonClicked(object sender, RoutedEventArgs e)
{
var textToSearch = search.Text;
var service = new QueryServiceSoapClient();

service.QueryCompleted += OnQueryCompleted;
service.QueryAsync(CreateSearchQuery(textToSearch));
}

Notice the CreateSearchQuery method? What’s that? At first you may thing you pass in a text keyword to the search service and it just returns a list of search results for you, but that’s not how it works.

Sharepoint uses CAML queries (Collaborative Application Markup Language) and as you guess it is an XML based language use to query Sharepoint for data. If you need in depth info on CAML query check out this article on Sharepoint Magazine, but in short we issue a request query packet and get the result out. Here’s how we provide a QueryPacket with search meta-data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private string CreateSearchQuery(string textToSearch)
{
return string.Format(@"<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'>{0}</QueryText>
</Context>
<Range>
<StartAt>1</StartAt>
<Count>50</Count>
</Range>
<EnableStemming>true</EnableStemming>
<TrimDuplicates>true</TrimDuplicates>
<IgnoreAllNoiseQuery>true</IgnoreAllNoiseQuery>
<ImplicitAndBehavior>true</ImplicitAndBehavior>
<IncludeRelevanceResults>true</IncludeRelevanceResults>
<IncludeSpecialTermResults>true</IncludeSpecialTermResults>
<IncludeHighConfidenceResults>true</IncludeHighConfidenceResults>
</Query>
</QueryPacket>", textToSearch);
}

Note that there is another query type (MSSQLFT) which uses FullText search to find data. Check this page on MSDN to see how it actually works.

The rest a no brainer. You need to parse the returned xml string and bind the result to your UI.

Search Result

Upon execution you may notice that you get a Not Found error returned by Silverlight webservice stack, as soon as you call the webservice. As with all WebServices, Sharepoint services should be configured for cross domain calls so Silverlight searches for a ClientAccessPolicy.xml file in the root of the IIS hosting Sharepoint. If the file is not there (or not configured correctly) you’ll get CommunicationException and the service call fails. So make sure you copy the file that allows your client to call the service to the root of the website, that is usually here:

1
%WinDir%\inetpub\wwwroot\wss\VirtualDirectories\%SitePort%

To check if the file is copied correctly, check it in your browser by pointing to the following address:

    http://sharepointmachine/ClientAccessPolicy.xml

Also if you get other webservice errors, make sure you have “disabled” anonymous access to your sharepoint site. Strange it may seem, but if you enable anonymous access to your sharepoint site, all webservice calls will be ignored.