How to: Access a Service from Silverlight using Visual Studio

This topic describes how to access a service from a Silverlight client using a proxy. A proxy is a class that helps you access a particular service, and is generated automatically using the Add Service Reference tool in Visual Studio 2008. You must generate a separate proxy for each service you want to access.

This topic assumes that you have already built a Silverlight-enabled Windows Communication Foundation (WCF) service by completing the procedures in the topic How to: Build a Service for Silverlight Clients.

The same procedure 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 steps described here. Instead, for procedures on how to access them, see Accessing HTTP-Based Services Directly.

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

  1. The steps for these tasks are described in the How to: Build a Service for Silverlight Clients procedure.

To add a Service Reference to the service

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

  2. Click the Discover button 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 the Discover button. Instead, enter the URL of the service (or for the service’s WSDL – Web Services Description Language document) into the Add Service Reference dialog box.

    Accept the 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 Page.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 in the Page() constructor.

    CustomerServiceClient proxy = new CustomerServiceClient();

    If you are unsure where to place code within the Page.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 – this event 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.

    proxy.CountUsersCompleted += new EventHandler<CountUsersCompletedEventArgs>(proxy_CountUsersCompleted);
    proxy.CountUsersAsync();
    
  2. The event handler specifies that the proxy_CountUsersCompleted method should be called when the service returns some data. We need to define and add this method in the Page class.

    void proxy_CountUsersCompleted(object sender, CountUsersCompletedEventArgs e)
    {
        userCountResult.Text = "Number of users: " + e.Result;
    }
    
    Cc197937.note(en-us,VS.95).gifNote:
    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.

  3. Follow a similar procedure to call the second GetUsers operation offered by the service. The complete code can be found at the end of this topic.

  4. 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>
    
  5. The control is now ready to use. Press Ctrl + F5 in Visual Studio 2008 to open the CustomerClientTestPage.aspx client page, which is automatically generated to test the Silverlight 2 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.

Error Conditions

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. The service you are attempting to connect to may not publish an appropriate cross-domain policy, and so access from browser-based applications may not be allowed. 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. Note that Silverlight does not let you distinguish between these errors or read SOAP Fault details, but you may still handle all these errors in the same way.

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 accessing the Result property when an error condition has occurred, an exception will be thrown. The following example shows how to make the event handler from the earlier example in this topic robust against errors.

void proxy_CountUsersCompleted(object sender, CountUsersCompletedEventArgs e)
{
    if (e.Error != null)
    {
       userCountResult.Text = "Number of users: " + e.Result;
    }
    else
    {
      userCountResult.Text = “Error getting the number of users”;
    }
}
Cc197937.note(en-us,VS.95).gif
Note: If you are running your Silverlight application under the Visual Studio 2008 debugger, with certain debugger settings execution may stop in case of an error, even if you are handling the error as shown above. If this happens, simply continue the execution and the error will be handled.

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

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 character 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 runtime. 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.

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

The default BasicHttpBinding binding will be appropriate for most scenarios, but may 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, since 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 Page.xaml.cs after completing all of the preceding procedures.

//Page.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 Page : UserControl
    {
        public Page()
        {
            // 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)
        {
            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 = "Number of users: " + e.Result;
            }
            else
            {
              userCountResult.Text = “Error getting the number of users”;
            }
        }
    }
} 

See Also

Change Date History Reason

1/7/2008

The error handling code was added to the sample and the alert about errors when using the Visual Studio debugger.

Confirmation that this feature was working correctly was not obtained until after Silverlight 2.0 RTM, so the documentation of it was delayed until now.

Send comments about this topic to Microsoft.

Tags :


Community Content

cfuller
Bug in proxy_CountUsersCompleted of your example source
I believe you want to say

if (e.Error == null)

rather than

if (e.Error != null)

as you have it.

The current logic does not work when we test. The exception gets called when we have successfully returned data from the service.

Tags :

Page view tracker