How to: Access a Service from Silverlight

Microsoft Silverlight will reach end of support after October 2021. Learn more.

This topic describes how to access a service from a Silverlight client by using a proxy. A proxy is a class that helps you access a particular service. The proxy can be generated automatically by using the Add Service Reference tool in Visual Studio 2010, which is the procedure used in this topic, or it can be generated by using the Silverlight Service Model Proxy Generation Tool (SLsvcutil.exe) using service metadata documents received from the target service. For more information about using the Proxy Generation Tool, see Using SLsvcUtil.exe to Access a Service.

Cc197937.note(en-us,VS.95).gifNote:
You must generate a separate proxy for each service you want to access.

A procedure similar to the one outlined here can also be used to access a public SOAP service, if you know the service address, and if the service allows access by browser applications from your application’s domain. For more information, see Accessing SOAP Services and Making a Service Available Across Domain Boundaries.

Some public services, such as plain HTTP or REST services, do not publish a computer-readable description of themselves, and therefore a proxy cannot be automatically generated for them. These services cannot be accessed by using the procedure described here. Instead, for instructions on how to access them, see Accessing HTTP and REST-Based Services Directly.

To create the Silverlight client application and add a Silverlight-enabled service

To add a Service Reference to the service

  1. Right-click the SilverlightApplication1 project in Solution Explorer and select Add Service Reference.

  2. Click Discover to find CustomerService.svc created in the How to: Build a Service for Silverlight Clients procedure. It should appear in the Services box.

    Cc197937.note(en-us,VS.95).gifNote:
    If you are using a SOAP service outside of your current solution, such as a public SOAP service, do not click Discover. Instead, enter the URL of the service (or of the service’s WSDL – Web Services Description Language document) into the Add Service Reference dialog box.

    Accept ServiceReference1 in the Namespace field and click OK.

  3. Notice that Solution Explorer now has added a folder called Service References. You can explore ServiceReference1 in that folder by right-clicking and selecting View in Object Browser. Note that it contains the SilverlightApplication1.ServiceReference1.CustomerServiceClient class and its methods. These are methods invoked to call the service.

To construct a proxy to the service

  1. Go to the MainPage.xaml.cs (code-behind) file in the client application and add the following using statements at the top of the page.

    using System.ServiceModel;
    using SilverlightApplication1.ServiceReference1;
    
  2. You must instantiate the Web service proxy before using the service. For example, you can do this within the scope of the MainPage() constructor.

    CustomerServiceClient proxy = new CustomerServiceClient();
    
    Cc197937.Tip(en-us,VS.95).gifTip:
    If you are unsure where to place code within the MainPage.xaml.cs file, in this step or in the following steps, consult the sample code summarized for this code-behind page at the bottom of this procedure.

    Note that by default, configuration information for the proxy (such as the Web service address) is read from the ServiceReferences.ClientConfig file. This file is automatically created by the Add Service Reference tool. For more information, see Configuring Web Service Usage in Silverlight Clients.

To call operations on the Web service

  1. All Web service calls in Silverlight are asynchronous. The proxy contains two members for each operation in the service: an asynchronous method and a completed event. For example, consider the CountUsers service operation. We first add an EventHandler to CountUsersCompleted within the scope of the MainPage() constructor. This is the event that will be invoked when the service returns the data we requested. After the event is set up, we are ready to make the call to the service by calling CountUsersAsync. The following sample shows the code for these two steps.

    proxy.CountUsersCompleted += new EventHandler<CountUsersCompletedEventArgs>(proxy_CountUsersCompleted);
    proxy.CountUsersAsync();
    
    Cc197937.Tip(en-us,VS.95).gifTip:
    Visual Studio makes it easy to write asynchronous code. Simply type proxy.CountUsersCompleted += and press the TAB key twice. The event handler and the event handler method will automatically be created for you.
  2. The proxy members needed for the asynchronous method and completed event of the GetUsers service operation within the scope of the MainPage() constructor, similarly, are:

    proxy.GetUserCompleted += new EventHandler<GetUserCompletedEventArgs>(proxy_GetUserCompleted);
    proxy.GetUserAsync(1);
    
  3. The event handler specifies that the proxy_CountUsersCompleted method should be called when the service returns some data. We need to define this method within the scope of the MainPage class in a way that handles errors robustly. To handle error conditions, you must detect the error by checking the Error property on the resulting event arguments, before accessing the Result property. If you try to access the Result property when an error condition has occurred, an exception will be thrown. The following example shows how to make the event handler robust against errors.

    void proxy_CountUsersCompleted(object sender, CountUsersCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            userCountResult.Text = “Error getting the number of users.”; 
        }
        else
        {
            userCountResult.Text = "Number of users: " + e.Result;
        }
    }
    

    Various errors may occur when calling services. For example, the service may not be available, it may not be configured to support protocols understood by Silverlight, or the service address may be wrong. Errors may also occur due to cross-domain access issues. For more information, see Making a Service Available Across Domain Boundaries.

    In another specific class of errors, there may be an error specific to a particular service that is sent as a SOAP Fault. This could be the case, for example, if you attempted to call GetUser with a non-existent user ID. For more information about handling faults, see Creating and Handling Faults in Silverlight.

    For more information about debugging error conditions, see Debugging Services for Silverlight Applications.

  4. Follow a similar procedure to call the second GetUsers operation offered by the service.

    void proxy_GetUserCompleted(object sender, GetUserCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            getUserResult.Text = "Error getting the user.";
        }
        else
        {
            getUserResult.Text = "User name: " + e.Result.Name + ", age: " + e.Result.Age + ", is member: " + e.Result.IsMember;
        }
    }
    
  5. To display the result of the Web service calls in a client control, open the Page.xaml file and add a StackPanel with two TextBlock controls to the Grid element.

    <StackPanel>
        <TextBlock x:Name="userCountResult" />
        <TextBlock x:Name="getUserResult" />
    </StackPanel>
    
  6. The control is now ready to use. Press CTRL + F5 in Visual Studio 2010 to open the CustomerClientTestPage.aspx client page, which is automatically generated to test the Silverlight 4 control. You should see the lines “Number of users: 2” and “User name: Paul, age: 24, is member: True” in the browser window on the test page.

Additional Features for Accessing Services

The following additional notes clarify and extend the procedure outlined above.

Data Binding

The types generated by the Add Service Reference tool are designed to make data binding scenarios easy. Most types implement the INotifyPropertyChanged interface, so that any updates to instances of these types will automatically update UI components. For the same reason, most collections are returned from services as instances of the generic ObservableCollection class by default. For more information, see the Data Binding section of the Silverlight documentation.

Alternative Approaches to Configuration

As mentioned before, the default proxy constructor configures the proxy based on information in the ServiceReferences.ClientConfig file.

CustomerServiceClient proxy = new CustomerServiceClient();

The configuration file contains the service address and binding information. Binding information informs Silverlight about the protocol details used to communicate with the service, such as the appropriate message encoding.

The configuration file may consist of multiple <endpoint> elements for the same service. This allows you to store multiple configurations for the same service and select one at run time. This approach is described in the Configuring Web Service Usage in Silverlight Clients topic.

Occasionally, you may want to eliminate the configuration system altogether, and specify the address and binding information in code. This is possible by using an appropriate proxy constructor. The following code shows an example of such a constructor that configures the client with a BasicHttpBinding.

CustomerServiceClient proxy = new CustomerServiceClient(new BasicHttpBinding(), new EndpointAddress("http://services.contoso.com/CustomerService.svc"));

The default BasicHttpBinding binding with defaults will be appropriate for most scenarios, and it can also be customized.

Alternative Asynchronous Invocation Model and Threading Issues

Usually, the event-based asynchronous model described previously raises the completion event on the same thread on which the service was called. This is convenient in many applications, because you often invoke services from the UI (User Interface) thread, and can update UI components (such as text boxes in our example) directly in the completion event handler.

Occasionally, you may want the completion event to be processed on a background thread. Either for this or for other reasons, you may want to use an alternative asynchronous invocation model based on the IAsyncResult mechanism and on Begin/End methods.

To use this model, you must first cast the proxy to an appropriate interface type. The interface type is generated automatically alongside the proxy by the Add Service Reference tool. You can then invoke the appropriate Begin method.

IAsyncResult iar = ((CustomerService)proxy).BeginGetUser(userId, GetUserCallback, proxy);

The last two parameters are the callback method to invoke (on a background thread) when the service call completes, and the proxy. The proxy is passed as a state object so that the callback method will be able to call the corresponding End method. You then need to implement the callback and call the appropriate End method.

static void GetUserCallback(IAsyncResult iar)
{
    User u = ((CustomerService)iar.AsyncState).EndGetUser(iar);

    string name = u.Name;

    // Use returned data ...
}

If an error occurs while invoking the service, the End method will throw an exception.

Example

The following is the summarized code of MainPage.xaml.cs after completing the preceding (but not the additional) procedures.

//MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ServiceModel;
using SilverlightApplication1.ServiceReference1;


namespace SilverlightApplication1
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            // Required to initialize variables
            InitializeComponent();

            CustomerServiceClient proxy = new CustomerServiceClient();

            proxy.CountUsersCompleted += new EventHandler< CountUsersCompletedEventArgs>(proxy_CountUsersCompleted);
            proxy.CountUsersAsync();

            proxy.GetUserCompleted += new EventHandler< GetUserCompletedEventArgs>(proxy_GetUserCompleted);
            proxy.GetUserAsync(1);
        }

        void proxy_GetUserCompleted(object sender, GetUserCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                getUserResult.Text = "Error getting the user.";
            }
            else
            {
                getUserResult.Text = "User name: " + e.Result.Name + ", age: " + e.Result.Age + ", is member: " + e.Result.IsMember;
            }
        }

        void proxy_CountUsersCompleted(object sender, CountUsersCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                userCountResult.Text = “Error getting the number of users.”; 
            }
            else
            {
                userCountResult.Text = "Number of users: " + e.Result;
            }
        }
    }
} 

See Also

Send comments about this topic to Microsoft.

Copyright © 2010 by Microsoft Corporation. All rights reserved.