Consuming Data from the Server Using WCF Services

Although this chapter primarily focuses on consuming data with RIA Services, it's worth briefly looking first at how you can consume data using plain old WCF Services.

images Workshop: Querying Data Exposed by a WCF Service

In Chapter 4, we created a WCF Service that returned a collection of Product entities from an Entity Framework model. You can consume data from a WCF Service in Silverlight in essentially the same way as you would in a Windows Forms or WPF application; you're just forced into using the asynchronous methods when using Silverlight, as the synchronous methods are not available.

images Note For each operation in your WCF Service (for example, GetProducts), the service reference proxy generator will generate a corresponding method (the operation's name, suffixed with Async; for example, GetProductsAsync) on the service reference proxy class that will begin the call to the server. A corresponding event will also be created (with the operation's name, suffixed with Completed; for example, GetProductsCompleted), that will be raised when the call to the server completes.

There are a number of ways you can connect to a WCF service. You can use the ChannelFactory class, or you can create a class that inherits from the generic System.ServiceModel.ClientBase class. However, the easiest way is to use a service reference proxy, which is the method we'll use in this workshop. We'll call the GetProducts method on the WCF Service we created in Chapter 4, and display the results in a DataGrid control.

  1. Using the AdventureWorks solution we've been working with in previous chapters, right-click the Silverlight project in Visual Studio's Solution Explorer tool window, and select Add Service Reference– from the context menu.
  2. Click the Discover button to automatically search for any WCF Services in your solution. The ProductService.svc service you created in Chapter 4 should appear in the list, as shown in Figure 5-1.
  3. You need to provide a namespace for all the classes that the service reference generator creates for you. Enter Services into the Namespace text box at the bottom of the window. Click OK. This will generate the service reference proxy for you, which you can see if you expand the Service References folder that has been added to your project.
    images

    Figure 5-1. Visual Studio's Add Service Reference window

    images Note You might recall from Chapter 4 that Silverlight does not support all the WCF bindings available with the full .NET Framework. If you attempt to add a reference to a service that has no endpoint using a binding supported by Silverlight, the service reference will still be added to your project, but a warning will appear in the Error List window stating that the endpoint is not compatible with Silverlight. Your project will compile, but attempting to make a call to the service will result in an InvalidOperationException exception.

    You'll note that a file named ServiceReferences.ClientConfig has been added to your project. As its name suggests, this file contains the configuration of the service references in your project.

    <configuration>
        <system.serviceModel>
            <bindings>
                <customBinding>
                    <binding name="CustomBinding_ProductService">
                        <binaryMessageEncoding />
                        <httpTransport maxReceivedMessageSize="2147483647"
                                       maxBufferSize="2147483647" />
                    </binding>
                </customBinding>
            </bindings>
            <client>
                <endpoint address="http://localhost:52878/ProductService.svc"
                    binding="customBinding"
                    bindingConfiguration="CustomBinding_ProductService"
                    contract="Services.ProductService"
                    name="CustomBinding_ProductService" />
            </client>
        </system.serviceModel>
    </configuration>

    As you can see, the configuration defines an endpoint that the service reference proxy will use to connect to the WCF Service on the server. Endpoints consist of an

    • Address,
    • Binding, and
    • Contract.

    The address points to the WCF Service's URL (when running locally using the ASP.NET Development Server). The endpoint's binding points to a custom binding that is also configured in the file (the custom binding uses binary message encoding for smaller packet sizes). The final piece, the contract, points to the class that the Add Service Reference window generated for us.

  4. Add a reference to your project to the System.Windows.Controls.Data.dll assembly. This assembly contains the DataGrid control. An alternative way to reference this assembly is to simply drag the DataGrid control from the toolbox onto a view's design surface.
  5. Add a new view to the Views folder in your application, named WCFServiceTestView.xaml, using the Silverlight Page item template. Add a DataGrid control to this view, and name it productDataGrid. You should have the following XAML:
    <navigation:Page x:Class="AdventureWorks.Views.WCFServiceTestView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
         mc:Ignorable="d"
         xmlns:navigation="clr-namespace:System.Windows.Controls;??
                                 assembly=System.Windows.Controls.Navigation"
         d:DesignWidth="640" d:DesignHeight="480"
         Title="WCFServiceTestView Page">

        <Grid x:Name="LayoutRoot">
            <sdk:DataGrid Name="productDataGrid" />
        </Grid>
    </navigation:Page>
  6. Open the code-behind for the view (WCFServiceTestView.xaml.cs). Add the following using statement to the top of the file:
    using AdventureWorks.Services;
  7. In the constructor, you can now instantiate the service reference proxy class, wire up an event handler to its GetProductsCompleted event, and call its GetProductsAsync method, as follows:
    public WCFServiceTestView()
    {
        InitializeComponent();

        ProductServiceClient service = new ProductServiceClient();
        service.GetProductsCompleted += service_GetProductsCompleted;
        service.GetProductsAsync();
    }

    In the completed event handler, you can then check if an error occurred; if not, you can assign the result to the DataGrid control's ItemSource property (which will display the results in the DataGrid):

    private void service_GetProductsCompleted(object sender,
                                              GetProductsCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            productDataGrid.ItemsSource = e.Result;
        }
        else
        {
            MessageBox.Show(e.Error.Message);
        }
    }

    Alternatively, instead of wiring up the event handler for the GetProductsCompleted event in the constructor, you can “inline” the call completed logic using an anonymous method, like so:

    public WCFServiceTestView()
    {
        InitializeComponent();

        ProductServiceClient service = new ProductServiceClient();

        service.GetProductsCompleted += (sender, e) =>
            {
                if (e.Error == null && !e.Cancelled)
                {
                    productDataGrid.ItemsSource = e.Result;
                }
                else
                {
                    MessageBox.Show(e.Error.Message);
                }
            };

        service.GetProductsAsync();
    }
  8. You can now run your application and navigate to this view. (You might want to add a menu item that points to it, as described in Chapter 3, or alternatively simply use #/WCFServiceTestView as the “bookmark” portion of the URL in your browser's address bar.) The DataGrid control will be populated with the data returned by the WCF Service.

images Note You can configure the URL for the WCF Service in the ServiceReferences.ClientConfig file, but sometimes you need to specify the correct URL at runtime. The constructor for the service reference proxy class has several overloads, some of which accept an endpoint address, to which you can pass the URL. Often, you will want to point to the service at the site of origin for the Silverlight application (i.e., the site from which the Silverlight application was downloaded). You can ascertain this URL using the Source property of the Application.Current.Host object.

Common Pitfalls

There are a few pitfalls to be aware of when calling WCF Services in Silverlight. As RIA Services are built upon WCF, these issues also apply to it as well.

Maximum Message Size

The WCF Service on the server has a limit to the maximum message size it will return as a response, and the Silverlight client also has a maximum message size that it will accept. Although the default maximum message size accepted by the Silverlight client is configured at an impossibly large 2 GB, the service in the Web project has a default maximum message size of 64 KB. Attempting to return a response larger than this from your service (common when returning large lists of data) will result in an exception being thrown. You can modify this limit by customizing your binding properties in the Web project's Web.config file, setting an alternative maximum message size (in bytes). That said, it's probably better to design your server/client communication to transfer smaller messages where possible. Unless the user requires all that data at the one time, you would be better aiming to minimize data traffic, and hence the time that the user is left waiting for a response from the server, sending only the data back to the client that the user requires at that time. For example, when displaying a list of data to the user, request the data in pages rather than as a single unit.

ASP.NET Session State

Despite Silverlight enforcing that server calls must be performed asynchronously, if you have ASP.NET session state turned on in your Web project, you will find that calls are executed on the server sequentially, resulting in the calls appearing slower than expected.

You can tell if ASP.NET session state is turned on by using a tool such as Fiddler (which you can download from www.fiddler2.com) to intercept the responses from the server. If a cookie with the name ASP.NET_SessionId appears in the header, then ASP.NET session state is turned on. Generally, ASP.NET session state will be turned on automatically when you add a Global.asax file to your project.

This behavior occurs only when using the browser networking stack, which is the default when the application is running inside the browser. To work around this behavior, you can either stop using ASP.NET session state or simply use the client networking stack instead (discussed in the section “Choosing a Networking Stack,” later in this chapter).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset