In part one of this series we built a simple Silverlight 2 application that could retrieve list information from SharePoint. In part two we will expand on how Silverlight connects to SharePoint web services and move beyond the default connectivity that you get when you add a service reference in Visual Studio. If you remember, when we added the service reference, the sharepoint server name and the full url to the web service was specified in th add service dialog, similar to what you see in the image below:
Pressing the OK button generated the web service proxy classes "SharePoint.ListsSoap" and "SharePoint.ListsSoapClient". At that time Visual Studio also generated a client configuration file called "ServiceReferences.ClientConfig", the contents of which in the default connectivity information used by the ListsSoapClient when connecting to the SharePoint web servce. An example of the default content generated in this file can be seen below:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ListsSoap" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://visiodemosrv/_vti_bin/lists.asmx" binding="basicHttpBinding"
bindingConfiguration="ListsSoap" contract="SharePoint.ListsSoap"
name="ListsSoap" />
</client>
</system.serviceModel>
</configuration>
Web service connectivity is defined in terms of a "binding" which discribes how the connection is made to the web service, and the "endpoint", which describes where to connection to the web service. The code from part one of our series uses this default configuration to connect to the SharePoint Lists web service with the following code:
private void btnGo_Click(object sender, RoutedEventArgs e)
{
try
{
ListsSoapClient listSoapClient = new ListsSoapClient();
listSoapClient.GetListCollectionCompleted += new EventHandler(listSoapClient_GetListCollectionCompleted);
listSoapClient.GetListCollectionAsync();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Failed to get list collection", MessageBoxButton.OK);
}
}
If we wish to change from http to https or change the SharePoint service we are connecting to we would have to change the user configuration file. To allow us to specify our connection information dynamically, at run time, will will need to modify our code. To move between HTTP and HTTPS protocols we will need to change the security mode of the binding. Possible values are:
For our purposes we will focus on only the first two: None (HTTP) and Transform (HTTPS).
private const string SERVICE_LISTS_URL = "/_vti_bin/lists.asmx";
///
/// Go get the collection of lists from SharePoint when the user presses "Go"
///
///
///
private void btnGo_Click(object sender, RoutedEventArgs e)
{
try
{
Uri serviceUri = new Uri(txtSharePointUrl.Text + SERVICE_LISTS_URL);
BasicHttpBinding binding;
if (serviceUri.Scheme == "https")
{
binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
}
else
{
binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
}
EndpointAddress endpoint = new EndpointAddress(serviceUri);
ListsSoapClient listSoapClient = new ListsSoapClient(binding, endpoint);
listSoapClient.GetListCollectionCompleted += new EventHandler(listSoapClient_GetListCollectionCompleted);
listSoapClient.GetListCollectionAsync();
}
catch (Exception exception)
{
handleException("Failed to get list collection", exception);
}
}
You will also notice that there is a reference to a text box control “m_txtSharePointUrl” to allow the user to specify the name of the sharepoint site we wish to read data from. I’ve modified the user interface to take this into account. The user interface now looks like:
and the XAML for the UI page is a follows:
<UserControl x:Class="SharePointListExample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition MaxHeight="25"/>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0">
<TextBox x:Name="txtOutput" IsReadOnly="True"></TextBox>
</ScrollViewer>
<StackPanel Grid.Row="1" Orientation="Horizontal" Background="LightGray">
<TextBlock Margin="5,0,5,0" VerticalAlignment="Center">Sharepoint Url:</TextBlock>
<TextBox MinWidth="100" x:Name="txtSharePointUrl" Text="http://mysharepointserver.com/sites/mysite"></TextBox>
<Button x:Name="btnGo" Margin="5,0,0,0" Content="Go" Click="btnGo_Click"/>
</StackPanel>
</Grid>
</UserControl>
You should also notice that I replace the exception handling with a more complex exception handler that will show us details of the exception message. The code for the new exception handler is shown below. In keeping with the aim of eventually turning this example into a real-world tool I have also started to include comment headers for each of the methods.
///
/// Handle exceptions by displaying them in message boxes.
///
/// The exception context
/// The exception to be handled
private void handleException(string context, Exception exception)
{
this.Dispatcher.BeginInvoke(delegate()
{
bool showExceptionDetail = this.ShowExceptionDetail;
string message = "";
Exception next = exception;
do
{
if (message.Length > 0)
{
message += ";" + Environment.NewLine;
}
if (next.Message == null || next.Message.Length == 0)
{
message += next.GetType().FullName;
}
else
{
message += next.Message;
}
if (showExceptionDetail)
{
if (next.Data.Count > 0)
{
bool first = true;
message += " {";
foreach (string key in next.Data.Keys)
{
if (first)
{
first = false;
}
else
{
message += ", ";
}
message += key + "=\"" + next.Data[key] + "\"";
}
message += "}";
}
if (next.InnerException != next)
{
next = next.InnerException;
continue;
}
}
next = null;
}
while (next != null);
MessageBox.Show(message, context, MessageBoxButton.OK);
});
}
Note that the exeception handler now uses a call to the Dispatcher in which to execute the code. This is because most of the web service calls are executed asynchronously and when completed, the thread that is executing the web service call back does not have access to the user interface, so calls to the UI, such as the call to MessageBox.Show will not work. The call to Dispatcher.BeginInvoke causes the code to be executed on the user interface thread of the page, so the call to MessageBox.Show will now work.
Now running the Silverlight application in debug mode allows us to specify the sharepoint site dynamically and retreive the same information as in part one.
Complete source for Part 2 of Practical Silverlight and SharePoint Integration can be found here: PracticalSilverlightAndSharePointIntegration.Part2.zip (1057 KB)
In the next part we will add data binding to our data and show how list item data can be retreaved using CAML queries.
Part One | Part Two | Part Three | Part Four (To be done)
(c) Copyright 2009 – Aaron G. Daisley-Harrison – All Rights Reserved.