Click to Rate and Give Feedback
MSDN
MSDN Library
.NET Development
Silverlight
 How to: Access a Service from Silve...
How to: Access a Service from Silverlight

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.
Tags What's this?: Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
the type or namespace name 'GetUserCompletedEventArgs' could not be found      Stromberg17   |   Edit   |   Show History
Hi, I have tried to implement this example but got the error: "the type or namespace name 'GetUserCompletedEventArgs' could not be found". Can someone help me with this issue? Thanks in advance. Stromberg17
Tags What's this?: Add a tag
Flag as ContentBug
The example generated errors after being deployed to IIS      jon4112   |   Edit   |   Show History
Hi there, I tried this example and it worked well under the VS2010 development environment. However, it always generated errors on the client side after being deployed to my IIS default web site. The error message suggest that a cross-domain policy isn't set in place. I put both crossdomain.xml and clientaccesspolicy.xml files at root of my IIS default web site, it didn't work either. However, there is no problem to access the service via tool WCF Test Client, i.e. all requests were replied with correct results. I'm not sure if this is a client issue or a configuration issue. You help is appreciated. $0Error example:$0 $0An error occurred while trying to make a request to URI 'http://localhost:3420/service1.svc'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You need to contact owner of the service ...$0 $0$0 $0 $0Update on 05/19/2011$0 $0Just found out that it is a client configuration issue. The URI generated by VS needs to be replaced by the URI of your IIS, i.e. 'http://www.yourdomain.com/service1.svc', when being deployed. Hence, the problem is gone$0
Tags What's this?: Add a tag
Flag as ContentBug
Help      Aktivo   |   Edit   |   Show History
All works fine, but in e.Result properties like Name, Age and IsMember is not visible.
e.Result.Name, e.Result.Age, e.Result.IsMember is not valid
only e.Result is valid.

Where is problem ?
Tags What's this?: Add a tag
Flag as ContentBug
Bug in proxy_CountUsersCompleted of your example source      cfuller   |   Edit   |   Show History
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.

Processing
© 2012 Microsoft. All rights reserved. Terms of Use | Trademarks | Privacy Statement
Page view tracker