WCF Services

You will no doubt be familiar with WCF if you have ever written an application (using another .NET technology, such as WPF, ASP.NET, etc.) that consumes data from a server. Let's take a look at how you can create and consume WCF Services in your Silverlight application.

A Short Overview of WCF

Microsoft introduced WCF as part of version 3.0 of the .NET Framework. WCF is a unified communication layer, designed to bring a wide array of messaging technologies, such as Web services and remoting, together in one technology-agnostic model. WCF enables you to write the messaging features for an application against this model, and then specify the actual technology to be used, referred to as bindings,  through configuration files. In other words, you can write the communication functionality for your application without worrying about what technology it will use and how that communication will take place, and without tying your application to a specific messaging technology.

The WCF model is broken into three components: the service's address, its bindings, and its contract, with a clear separation maintained between each. You define the contract—that is, the functionality to be exposed by your service—and then you can configure the address and the bindings that the service supports to form a service endpoint.

If you've built and consumed WCF Services previously with other .NET technologies, you'll be able to use your existing knowledge when working with WCF Services in Silverlight. However, there are just a few slight differences and limitations that you'll need to be aware of. Let's look at those differences and limitations now.

The Silverlight-Enabled WCF Service Item Template

It's possible to consume existing WCF Services in Silverlight, assuming they are configured to use a binding (i.e., messaging technology) supported by Silverlight. Silverlight has a limited number of bindings that it supports, and the binding used by many WCF Services by default (wsHttpBinding) is one of those not supported by Silverlight. Therefore, you will need to configure a binding supported by Silverlight for the WCF service on the server before it can be consumed by a Silverlight application. The bindings supported by Silverlight applications are detailed in the next section.

When creating a new WCF service, there is an item template that you can use to create a WCF service that can be consumed by a Silverlight application “out of the box.” When you add a new item to your project, you will find an item template named “Silverlight-enabled WCF Service” under the Silverlight category. This item template creates a WCF service that automatically implements a binding supported by Silverlight, so it's the best method of getting a WCF service up and running that can be consumed by a Silverlight application. Let's say you add a new WCF service using the Silverlight-enabled WCF Service item template to your AdventureWorks.Web project, named ProductService.svc. If you now open up the web.config file in the project, you will see that a new custom binding has been defined:

<customBinding>
    <binding name="AdventureWorks.Web.ProductService.customBinding0">
         <binaryMessageEncoding />
         <httpTransport />
    </binding>
</customBinding>

An endpoint has been configured for the service that uses this binding:

<services>
    <service name="AdventureWorks.Web.ProductService">
    <endpoint address="” binding="customBinding"
              bindingConfiguration=
                        “AdventureWorks.Web.ProductService.customBinding0"
              contract="AdventureWorks.Web.ProductService” />
    <endpoint address="mex” binding="mexHttpBinding"
              contract="IMetadataExchange” />
    </service>
</services>

As you can see, a custom binding is defined that binary-encodes the messages before sending them over an HTTP connection. The reason that we need to define a custom binding is because none of the bindings supported by Silverlight implement binary encoding of messages. By binary-encoding messages (instead of sending them as plain text), you have much smaller messages passed between the server and the client. Therefore, it's worth creating a custom binding in order to be able to use just that feature.

images Note WCF RIA Services are also automatically configured to use a custom binding that binary-encodes messages, in much the same way.

If you now look at the code for the service that the item template generated for you, you will find the following code:

using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;

namespace AdventureWorks.Web
{
    [ServiceContract(Namespace = “")]
    [SilverlightFaultBehavior]
    [AspNetCompatibilityRequirements(RequirementsMode =
                                 AspNetCompatibilityRequirementsMode.Allowed)]
    public class ProductService
    {
        [OperationContract]
        public void DoWork()
        {
            // Add your operation implementation here.
            return;
        }

        // Add more operations here and mark them with [OperationContract].
    }
}

The SilverlightFaultBehavior attribute applied to the service's class is particularly worth noting. When an error is thrown in a WCF service, this exception will normally be returned and raised on the client. However, Silverlight applications don't exhibit this behavior because they use the browser's networking stack (by default), and this stack can only return the 200 and 404 HTTP status codes to plug-ins. WCF Services return exceptions using the 500 HTTP status code (Internal Server Error) and, consequently, are not passed through to the Silverlight application. Instead, the browser will pass this to the Silverlight plug-in as HTTP status code 404, which represents the Not Found error. Hence, your server may throw an exception—for example, a concurrency exception—but your Silverlight application will throw a 404 Not Found exception in response. Of course, this error is incredibly misleading in this context, and can create quite some confusion. Once you understand why this happens, you'll still want to know on the client what exception occurred on the server so that you can notify the user or handle it accordingly.

images Note This behavior does not apply when using the client networking stack. We'll discuss the browser versus the client networking stacks in Chapter 5.

The SilverlightFaultBehavior attribute changes this behavior by implementing a custom endpoint behavior that inspects all outgoing messages looking for faults—that is, the result of exceptions being raised. When a fault is found, it simply changes the HTTP status code to 200 (OK) so that the response makes it through the browser's networking stack and to the Silverlight plug-in.

The client will now know that an exception was thrown on the server, but it still won't know what exception was thrown, because, for security reasons, exception details are not returned to the client by default. You can change this behavior, though, by changing the IncludeExceptionDetailInFaults attribute in the web.config file to true. The details of any exception thrown by the server will now make their way to the client.

It's also worth noting the AspNetCompatibilityRequirements attribute applied to the service's class. If you have ASP.NET compatibility enabled for your Web project, enabled by setting the aspNetCompatibilityMode property of the serviceHostingEnvironment element in the web.config file to true, you must decorate your service class with this attribute, and set its RequirementsMode property to either Allowed or Required. Otherwise, you will receive an error when you try to create a service reference in your Silverlight project for this service.

As you can see, the Silverlight-enabled WCF Service item template makes generating a WCF service suitable for consumption by a Silverlight application much easier.

Supported Bindings

As previously mentioned, the biggest limitation to consuming WCF Services in Silverlight is that not all bindings (messaging technologies) supported by WCF in the full .NET Framework are supported by Silverlight applications. Therefore, you must ensure that the WCF service that you wish to consume is actually configured to use a binding that Silverlight supports. Silverlight supports the following bindings:

  • basicHttpBinding: Uses the XML-based SOAP 1.1 protocol when communicating with the server. This is the protocol used by the older-style ASMX Web services, and sends messages in clear text over HTTP.
  • pollingDuplexHttpBinding: Enables the server to push messages to the client, in addition to simply handling client requests. As its name suggests, this binding works over HTTP, with the client using HTTP long-polling the server (behind the scenes), waiting for it to send it a message. This is useful when you want the server to send notifications to the clients, although the TCP binding is now a better performing choice to implement this type of behavior.
  • netTcpBinding: Used for similar purposes as pollingDuplexHttpBinding; however, instead of working over HTTP, it uses the net.tcp protocol. The performance of this binding is much better than pollingDuplexHttpBinding (primarily because there is no polling of the server); however, it is better suited to intranet scenarios, as it uses ports other than HTTP port 80 (although it's restricted by Silverlight to ports 4502 to 4534), which are often blocked by firewalls. Issues that you might face when using this binding include the fact that you cannot use transport-level security (it's not supported by Silverlight with the net.tcp protocol), there are a number of features you need to configure on your machine to support net.tcp communication, and you need to expose a socket policy file on port 943 in order to permit TCP connections from Silverlight applications.
  • customBinding: Enables you to tailor a binding to suit your requirements where a standard binding matching these requirements does not exist. Defining a custom binding enables you to customize the configuration of the various layers forming the binding, which includes the encoding of the messages (such as clear text, binary, etc.) and the transport over which they will be transferred (such as HTTP, HTTPS, TCP, etc.).

images Note The wsHttpBinding often used by the default endpoints configured by Visual Studio for WCF Services is not supported in Silverlight. Therefore, you will need to explicitly define an additional endpoint or modify the existing configuration of an endpoint that implements a binding supported by Silverlight. If you are creating the WCF service yourself, use the Silverlight-enabled WCF Service item template instead of the standard WCF Service item template, which will be configured in a manner friendly to being consumed by a Silverlight application, using a binding supported by Silverlight, and allowing the service to run in ASP.NET compatibility mode.

Sharing Code and Business Objects Between the Server and Client

One of the great features of RIA Services is the ability to share code, business objects, and business logic between the server and the client. However, it does this via code generation, generating code into the client project, corresponding to the code written in the server project, which some developers don't like and, hence, prefer to use plain WCF Services instead. There is, however, a little-known method for sharing code between the server and client project when using plain WCF Services, using a class library project containing the common code. The trick is to put the classes and shared code in a Silverlight Class Library project, and then add a reference to this assembly to both your Silverlight and Web projects. Specifically create this project as a Silverlight class library, rather than one targeting the full .NET Framework, because you can add a reference only to an assembly targeting the Silverlight runtime to a Silverlight project; however, projects targeting the full .NET Framework can reference assemblies that target the Silverlight runtime. Now you have any code and business objects that you include in this assembly shared between both the client and the server.

images Note You can alternatively use the Portable Library Tools instead of a Silverlight class library. Class libraries created using these tools can be run on a variety of .NET-based platforms (.NET 4.0, Silverlight, Windows Phone 7) without the need to recompile your project. You can get the Portable Library Tools here: http://visualstudiogallery.msdn.microsoft.com/b0e0b5e9-e138-410b-ad10-00cb3caf4981/.

Note that this still leaves you the task of manually populating your business objects after data has been retrieved from the server. This leads to trick number two: when you create your WCF service in the server project, expose data using the business objects from this shared class library. Usually, adding a service reference to a project creates a proxy containing objects with the structure matching the objects being exposed by the service. It then populates these proxy objects with data returned from the server, and accepts objects of these types only when sending data back to the server. However, you can configure your service reference to populate the types defined in one or more given assemblies, instead of populating the proxy objects. After selecting the service you want to add a reference to, in the Add Service Reference dialog, click the Advanced button to open the Service Reference Settings dialog. Ensure that the “Reuse types in referenced assemblies” check box is selected. You can then select specific assemblies for it to use, or have it search for matching types in all the assemblies referenced by the project. This means that it will automatically populate objects from the shared assembly when you request data from the server, and accept objects of those types when you pass data back to the server, thus saving you the need to copy the data between the service's proxy objects and the business objects from your shared assembly when communicating with the WCF service.

images Workshop: Creating a WCF Service

In this workshop, we'll create a WCF service that exposes a collection of Product entities from our Entity Framework model.

  1. Add a new item to the AdventureWorks.Web project, named ProductService.svc, using the Silverlight-enabled Web Service item template.
  2. Remove the DoWork operation that was created by the item template, as the template created it for demonstration purposes only. You should be left with the following code in the file:
    using System;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Activation;

    namespace AdventureWorks.Web
    {
        [ServiceContract(Namespace = “")]
        [SilverlightFaultBehavior]
        [AspNetCompatibilityRequirements(RequirementsMode =
                                     AspNetCompatibilityRequirementsMode.Allowed)]
        public class ProductService
        {
      
        }
    }
  3. Add a using statement to the top of the file for the System.Collections.Generic namespace.
    using System.Collections.Generic;
  4. It's not essential to do so, but it's recommended that you set a namespace for the service contract, by setting the Namespace property of the ServiceContract attribute applied to the class. This will be used to help maintain the uniqueness of your service's contract.
    [ServiceContract(Namespace = “http://www.apress.com")]
  5. Create a method named GetProducts, with a return type of IEnumerable<Product>. Decorate this method with the OperationContract attribute so that it will be exposed as a service operation.
    [OperationContract]
    public IEnumerable<Product> GetProducts()
    {

    }
  6. In this method, we need to get a collection of Product entities from our Entity Framework model, and return them as the method's result.
    [OperationContract]
    public IEnumerable<Product> GetProducts()
    {
        AdventureWorksEntities context = new AdventureWorksEntities();
        context.ContextOptions.LazyLoadingEnabled = false;
        return context.Products;
    }

    imagesNote Notice how we're setting the LazyLoadingEnabled property of the entity model's context to false. If we didn't do this, as the Product entities are being serialized, the serializer would attempt to also serialize the related data for each Product entity (and their related data, and so on), resulting in numerous queries to the database and ultimately the operation call timing out. Turning off lazy loading will prevent related data from being “lazily loaded” from the database, and return only the Product entities (and any data that has been explicitly loaded).

  7. The full code for your service should now be as follows, and is ready for consumption by a Silverlight application. We'll look and how you do so in Chapter 5.
    using System;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.Data.Objects;
    using System.Collections.Generic;

    namespace AdventureWorks.Web
    {
        [ServiceContract(Namespace = “http://wwww.apress.com")]
        [SilverlightFaultBehavior]
        [AspNetCompatibilityRequirements(RequirementsMode =
                                     AspNetCompatibilityRequirementsMode.Allowed)]
        public class ProductService
        {
            [OperationContract]
            public IEnumerable<Product> GetProducts()
            {
                AdventureWorksEntities context = new AdventureWorksEntities();
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.Products;
            }
        }
    }
..................Content has been hidden....................

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