Buy this Book
Print Book $44.99 PDF $31.99 Read it Now!
Print Book £31.99
Add to UK Cart
Reprint Licensing

Programming WCF Services
Programming WCF Services

By Juval Löwy
Book Price: $44.99 USD
£31.99 GBP
PDF Price: $31.99

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: WCF Essentials
This chapter describes the essential concepts and building blocks of WCF and its architecture, enabling you to build simple services. You will learn the basic terms regarding addresses, bindings, contracts, and endpoints; see how to host a service, learn how to write a client; and understand some related topics, such as in-proc hosting and reliability. Even if you are already familiar with the basic concepts of WCF, I recommend you give this chapter at least a cursory reading, not only to ensure you have a solid foundation, but also because some of the helper classes and terms introduced here will be used and extended throughout the book.
Windows Communication Foundation (WCF) is an SDK for developing and deploying services on Windows. WCF provides a runtime environment for your services, enabling you to expose CLR types as services, and to consume other services as CLR types. Although in theory you could build services without WCF, in practice building services is significantly easier with WCF. WCF is Microsoft's implementation of a set of industry standards defining service interactions, type conversion, marshaling, and various protocols' management. Because of that, WCF provides interoperability between services. WCF provides developers with the essential off-the-shelf plumbing required by almost any application, and as such, it greatly increases productivity. The first release of WCF provides many useful facilities for developing services, such as hosting, service instance management, asynchronous calls, reliability, transaction management, disconnected queued calls, and security. WCF also has an elegant extensibility model that you can use to enrich the basic offering. In fact, WCF itself is written using this extensibility model. The rest of the chapters in this book are dedicated to those aspects and features. Most all of the WCF functionality is included in a single assembly called System.ServiceModel.dll in the System.ServiceModel namespace.
WCF is part of .NET 3.0 and requires .NET 2.0, so it can only run on operation systems that support it. Presently this list consists of Windows Vista (client and server), Windows XP SP2, and Windows Server 2003 SP1 or their later versions.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is WCF?
Windows Communication Foundation (WCF) is an SDK for developing and deploying services on Windows. WCF provides a runtime environment for your services, enabling you to expose CLR types as services, and to consume other services as CLR types. Although in theory you could build services without WCF, in practice building services is significantly easier with WCF. WCF is Microsoft's implementation of a set of industry standards defining service interactions, type conversion, marshaling, and various protocols' management. Because of that, WCF provides interoperability between services. WCF provides developers with the essential off-the-shelf plumbing required by almost any application, and as such, it greatly increases productivity. The first release of WCF provides many useful facilities for developing services, such as hosting, service instance management, asynchronous calls, reliability, transaction management, disconnected queued calls, and security. WCF also has an elegant extensibility model that you can use to enrich the basic offering. In fact, WCF itself is written using this extensibility model. The rest of the chapters in this book are dedicated to those aspects and features. Most all of the WCF functionality is included in a single assembly called System.ServiceModel.dll in the System.ServiceModel namespace.
WCF is part of .NET 3.0 and requires .NET 2.0, so it can only run on operation systems that support it. Presently this list consists of Windows Vista (client and server), Windows XP SP2, and Windows Server 2003 SP1 or their later versions.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Services
A service is a unit of functionality exposed to the world. In that respect, it is the next evolutionary step in the long journey from functions to objects to components to services. Service-orientation (SO) is an abstract set of principles and best practices for building SO applications. If you are unfamiliar with the principles of service-orientation, Appendix A provides a concise overview and motivation for using service-orientation. The rest of this book assumes you are familiar with these principles. A service-oriented application (SOA) aggregates services into a single logical application similar to the way a component-oriented application aggregates components or an object-oriented application aggregates objects, as shown in Figure 1-1.
Figure 1-1: A service-oriented application
The services can be local or remote, developed by multiple parties using any technology, versioned independently, and even execute on different timelines. Inside a service, you will find concepts such as languages, technologies, platforms, versions, and frameworks, yet between services, only prescribed communication patterns are allowed.
The client of a service is merely the party consuming its functionality. The client can be literally anything—a Windows Forms class, an ASP.NET page, or another service.
Clients and services interact by sending and receiving messages. Messages may transfer directly from client to service or via an intermediary. With WCF, all messages are SOAP messages. Note that the messages are independent of transport protocols—unlike Web services, WCF services may communicate over a variety of transports, not just HTTP. WCF clients may interoperate with non-WCF services, and WCF services can interact with non-WCF clients. That said, typically if you develop both the client and the service, you could construct the application so that both ends require WCF to utilize WCF-specific advantages.
Because the making of the service is opaque from the outside, a WCF service typically exposes metadata describing the available functionality and possible ways of communicating with the service. The metadata is published in a predefined, technology-neutral way, such as using WSDL over HTTP-GET, or an industry standard for metadata exchange. A non-WCF client can import the metadata to its native environment as native types. Similarly, a WCF client can import the metadata of a non-WCF service and consume it as native CLR classes and interfaces.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Addresses
In WCF, every service is associated with a unique address. The address provides two important elements: the location of the service and the transport protocol or transport schema used to communicate with the service. The location portion of the address indicates the name of the target machine, site, or network; a communication port, pipe, or queue; and an optional specific path or URI. A URI is a Universal Resource Identifier, and can be any unique string, such as the service name or a GUID.
WCF 1.0 supports the following transport schemas:
  • HTTP
  • TCP
  • Peer network
  • IPC (Inter-Process Communication over named pipes)
  • MSMQ
Addresses always have the following format:
[base address]/[optional URI]
The base address is always in this format:
[transport]://[machine or domain][:optional port]
Here are a few sample addresses:
http://localhost:8001
http://localhost:8001/MyService
net.tcp://localhost:8002/MyService
net.pipe://localhost/MyPipe
net.msmq://localhost/private/MyService
net.msmq://localhost/MyService
The way to read an address such as
http://localhost:8001
is like this: "Using HTTP, go to the machine called localhost, where on port 8001 someone is waiting for my calls."
If there is also a URI such as:
http://localhost:8001/MyService
then the address would read as follows: "Using HTTP, go to the machine called localhost, where on port 8001 someone called MyService is waiting for my calls."
TCP addresses use net.tcp for the transport, and typically include a port number such as:
net.tcp://localhost:8002/MyService
When a port number is not specified, the TCP address defaults to port 808:
net.tcp://localhost/MyService
It is possible for two TCP addresses (from the same host, which will be discussed more later on in this chapter) to share a port:
net.tcp://localhost:8002/MyService
net.tcp://localhost:8002/MyOtherService
TCP-based addresses are used throughout this book.
You can configure TCP-based addresses from different hosts to share a port.
HTTP addresses use http for transport, and can also use
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Contracts
In WCF, all services expose contracts. The contract is a platform-neutral and standard way of describing what the service does. WCF defines four types of contracts.
Service contracts
Describe which operations the client can perform on the service. Service contracts are the subject of the next chapter, but are used extensively in every chapter in this book.
Data contracts
Define which data types are passed to and from the service. WCF defines implicit contracts for built-in types such as int and string, but you can easily define explicit opt-in data contracts for custom types. Chapter 3 is dedicated to defining and using data contracts, and subsequent chapters make use of data contracts as required.
Fault contracts
Define which errors are raised by the service, and how the service handles and propagates errors to its clients. Chapter 6 is dedicated to defining and using fault contracts.
Message contracts
Allow the service to interact directly with messages. Message contracts can be typed or untyped, and are useful in interoperability cases and when there is an existing message format you have to comply with. As a WCF developer, you should use message contracts only rarely, so this book makes no use of message contracts.
The ServiceContractAttribute is defined as:
[AttributeUsage(AttributeTargets.Interface|AttributeTargets.Class,
                Inherited = false)]
public sealed class ServiceContractAttribute : Attribute
{
   public string Name
   {get;set;}
   public string Namespace
   {get;set;}
   //More members
}
This attribute allows you to define a service contract. You can apply the attribute on an interface or a class, as shown in Example 1-1.
Example 1-1. Defining and implementing a service contract
[ServiceContract]
interface IMyContract
{
   [OperationContract]
   string MyMethod(string text);

   //Will not be part of the contract
   string MyOtherMethod(string text);
}
class MyService : IMyContract
{
   public string MyMethod(string text)
   {
      return "Hello " + text;
   }
   public string MyOtherMethod(string text)
   {
      return "Cannot call this method over WCF";
   }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Hosting
The WCF service class cannot exist in a void. Every WCF service must be hosted in a Windows process called the host process. A single host process can host multiple services, and the same service type can be hosted in multiple host processes. WCF makes no demand on whether or not the host process is also the client process. Obviously, having a separate process advocates fault and security isolation. It is also immaterial who provides the process or what kind of a process is involved. The host can be provided by IIS, by the Widows Activation Service (WAS) on Windows Vista, or by the developer as part of the application.
A special case of hosting is in-process hosting, or in-proc for short, where the service resides in the same process as the client. The host for the in-proc case is, by definition, provided by the developer.
The main advantage of hosting a service in the Microsoft Internet Information Server (IIS) web server is that the host process is launched automatically upon the first client request, and you rely on IIS to manage the life cycle of the host process. The main disadvantage of IIS hosting is that you can only use HTTP. With IIS5, you are further restricted to having all services use the same port number.
Hosting in IIS is very similar to hosting a classic ASMX web service. You need to create a virtual directory under IIS and supply a .svc file. The .svc file functions similar to an .asmx file, and is used to identify the service code behind the file and class. Example 1-2 shows the syntax for the .svc file.
Example 1-2. A .svc file
<%@ ServiceHost
       Language   = "C#"
       Debug      = "true"
       CodeBehind = "~/App_Code/MyService.cs"
       Service    = "MyService"
%>
You can even inject the service code inline in the .svc file, but that is not advisable, as is the case with ASMX web services.
When you use IIS hosting, the base address used for the service always has to be the same as the address of the .svc file.

Section 1.5.1.1: Using Visual Studio 2005

Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Bindings
There are multiple aspects of communication with any given service, and there are many possible communication patterns: messages can be synchronous request/reply or asynchronous fire-and-forget; messages can be bidirectional; messages can be delivered immediately or queued; and the queues can be durable or volatile. There are many possible transport protocols for the messages, such as HTTP (or HTTPS), TCP, P2P (peer network), IPC (named pipes), or MSMQ. There are a few possible message encoding options: you can chose plain text to enable interoperability, binary encoding to optimize performance, or MTOM (Message Transport Optimization Mechanism) for large payloads. There are a few options for securing messages: you can choose not to secure them at all, to provide transport-level security only, to provide message-level privacy and security, and of course there are numerous ways for authenticating and authorizing the clients. Message delivery might be unreliable or reliable end-to-end across intermediaries and dropped connections, and the messages might be processed in the order they were sent or in the order they were received. Your service might need to interoperate with other services or clients that are only aware of the basic web service protocol, or they may be capable of using the score of WS-* modern protocols such as WS-Security and WS-Atomic Transactions. Your service may need to interoperate with legacy clients over raw MSMQ messages, or you may want to restrict your service to interoperate only with another WCF service or client.
If you start counting all the possible communication and interaction options, the number of permutations is probably in the tens of thousands. Some of those choices may be mutually exclusive, and some may mandate other choices. Clearly, both the client and the service must be aligned on all these options in order to communicate properly. Managing this level of complexity adds no business value to most applications, and yet the productivity and quality implications of making the wrong decisions are severe.
To simplify these choices and make them more manageable, WCF groups together a set of such communication aspects in bindings. A
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Endpoints
Every service is associated with an address that defines where the service is, a binding that defines how to communicate with the service, and a contract that defines what the service does. This triumvirate governing the service is easy to remember as the ABC of the service. WCF formalizes this relationship in the form of an endpoint. The endpoint is the fusion of the address, contract, and binding (see Figure 1-5).
Figure 1-5: The endpoint
Every endpoint must have all three elements, and the host exposes the endpoint. Logically, the endpoint is the service's interface, and is analogous to a CLR or COM interface. Note in Figure 1-5 the use of the traditional "lollipop" to denote an endpoint.
Conceptually, even in C# or VB, an interface is an endpoint: the address is the memory address of the type's virtual table, the binding is CLR JIT compiling, and the contract is the interface itself. Because in classic .NET programming you never deal with addresses or bindings, you take them for granted. In WCF the address and the binding are not ordained, and need to be configured.
Every service must expose at least one business endpoint and each endpoint has exactly one contract. All endpoints on a service have unique addresses, and a single service can expose multiple endpoints. These endpoints can use the same or different bindings and can expose the same or different contracts. There is absolutely no relationship between the various endpoints a service provides.
It is important to point out that nothing in the service code pertains to its endpoints and they are always external to the service code. You can configure endpoints either administratively using a config file or programmatically.
Configuring an endpoint administratively requires placing the endpoints in the hosting process' config file. For example, given this service definition:
namespace MyNamespace
{
   [ServiceContract]
   interface IMyContract
   {...}
   class MyService : IMyContract
   {...}
}
Example 1-6 shows the required entries in the config file. Under each service type you list its endpoints.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Metadata Exchange
A service has two options for publishing its metadata. You can provide the metadata over the HTTP-GET protocol, or you can use a dedicated endpoint, discussed later. WCF can provide the metadata over HTTP-GET automatically for your service; all you need is to enable it by adding an explicit service behavior. Behaviors are described in subsequent chapters. For now, all you need to know is that a behavior is a local aspect of the service, such as whether or not it wants to exchange its metadata over HTTP-GET. You can add this behavior administratively or programmatically. Example 1-10 shows a host application config file, where both hosted services reference a custom behavior section that enables the metadata exchange over HTTP-GET. The address the clients need to use for the HTTP-GET is the registered HTTP base address of the service. You can also specify in the behavior an external URL for this purpose.
Example 1-10. Enabling metadata exchange behavior using a config file
<system.serviceModel>
   <services>
      <service name = "MyService" behaviorConfiguration = "MEXGET">
         <host>
            <baseAddresses>
               <add baseAddress = "http://localhost:8000/"/>
            </baseAddresses>
         </host>
         ...
      </service>
      <service name = "MyOtherService" behaviorConfiguration = "MEXGET">
         <host>
            <baseAddresses>
               <add baseAddress = "http://localhost:8001/"/>
            </baseAddresses>
         </host>
         ...
      </service>
   </services>
   <behaviors>
      <serviceBehaviors>
         <behavior name = "MEXGET">
            <serviceMetadata httpGetEnabled = "true"/>
         </behavior>
      </serviceBehaviors>
   </behaviors>
</system.serviceModel>
Once you have enabled the metadata exchange over HTTP-GET, you can navigate to the HTTP base address (if present) using a browser. If all is well, you will get a confirmation page, such as the one shown in Figure 1-6, letting you know that you have successfully hosted a service. The confirmation page is unrelated to IIS hosting, and you can use a browser to navigate to the service address even when self-hosting.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Client-Side Programming
To invoke operations on the service, the client first needs to import the service contract to the client's native representation. If the client uses WCF, the common way of invoking operations is to use a proxy. The proxy is a CLR class that exposes a single CLR interface representing the service contract. Note that if the service supports several contracts (over at least as many endpoints), the client needs a proxy per contract type. The proxy provides the same operations as service's contract, but also has additional methods for managing the proxy life cycle and the connection to the service. The proxy completely encapsulates every aspect of the service: its location, its implementation technology and runtime platform, and the communication transport.
You can use Visual Studio 2005 to import the service metadata and generate a proxy. If the service is self-hosted, first launch the service and then select Add Service Reference... from the client project's context menu. If the service is hosted in IIS or the WAS, there is no need to pre-launch the service. Interestingly enough, if the service is self-hosted in another project in the same solution as the client project, you can launch the host in Visual Studio 2005 and still add the reference, because unlike most project settings, this option is not disabled during a debug session (see Figure 1-9).
Figure 1-9: Generate a proxy using Visual Studio 2005
This brings up the Add Service Reference dialog box, where you need to supply the base address of the service (or a base address and a MEX URI) and the namespace to contain the proxy.
Instead of Visual Studio 2005, you can use the SvcUtil.exe command-line utility. You need to provide SvcUtil with the HTTP-GET address or the metadata exchange endpoint address and, optionally, with a proxy filename. The default proxy filename is output.cs but you can also use the /out switch to indicate a different name.
For example, if you're hosting the service MyService in IIS or the WAS, and have enabled metadata public sharing over HTTP-GET, simply run this command line:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Programmatic Versus Administrative Configuration
The two techniques shown so far for configuring both the client and service complement each other. Administrative configuration gives you the option to change major aspects of the service and the client post-deployment, without even the need to rebuild or redeploy. The major downside of administrative configuration is that it is not type-safe, and configuration errors will only be discovered at runtime.
Programmatic configuration is useful when the configuration decision is either completely dynamic—when it is taken at runtime based on the current input or conditions—or when the decision is static and never changes, in which case you might as well hardcode it. For example, if you are interested in hosting in-proc calls only, you might as well hardcode the use of the NetNamedPipeBinding and its configuration. However, by and large, most clients and services do resort to using a config file.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
WCF Architecture
So far in this chapter, I've covered all that is required to set up and consume simple WCF services. However, as described in the rest of the book, WCF offers immensely valuable support for reliability, transactions, concurrency management, security, and instance activation, all of which rely on the WCF interception-based architecture. Having the client interact with a proxy means that WCF is always present between the service and the client, intercepting the call and performing pre- and post-call processing. The interception starts when the proxy serializes the call stack frame to a message and sends the message down a chain of channels. The channel is merely an interceptor, whose purpose is to perform a specific task. Each client-side channel does pre-call processing of the message. The exact structure and composition of the chain depends mostly on the binding. For example, one of the channels may be responsible for encoding the message (binary, text, or MTOM), another for passing security call context, another for propagating the client transaction, another for managing the reliable session, another for encrypting the message body (if so configured), and so on. The last channel on the client side is the transport channel, which sends the message over the configured transport to the host.
On the host side, the message goes through a chain of channels as well, which perform host-side pre-call processing of the message. The first channel on the host side is the transport channel, which receives the message from the transport. Subsequent channels perform various tasks, such as decryption of the message body, decoding of the message, joining the propagated transaction, setting the security principal, managing the session, and activating the service instance. The last channel on the host side passes the message to the dispatcher. The dispatcher converts the message to a stack frame and calls the service instance. This sequence is depicted in Figure 1-11.
Figure 1-11: The WCF architecture
The service has no way of knowing it was not called by a local client. In fact, it
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Working with Channels
You can use channels directly to invoke operations on the service without ever resorting to using a proxy class. The ChannelFactory<T> class (and its supporting types), shown in Example 1-21, enables you to create a proxy on the fly.
Example 1-21. TheChannelFactory<T> class
public class ContractDescription
{
   public Type ContractType
   {get;set;}
   //More members
}

public class ServiceEndpoint
{
   public ServiceEndpoint(ContractDescription contract,Binding binding,
                                                          EndpointAddress address);
   public EndpointAddress Address
   {get;set;}
   public Binding Binding
   {get;set;}
   public ContractDescription Contract
   {get;}
   //More members
}

public abstract class ChannelFactory : ...
{
   public ServiceEndpoint Endpoint
   {get;}
   //More members
}
public class ChannelFactory<T> : ChannelFactory,...
{
   public ChannelFactory(ServiceEndpoint endpoint);
   public ChannelFactory(string configurationName);
   public ChannelFactory(Binding binding,EndpointAddress endpointAddress);
   public static T CreateChannel(Binding binding,EndpointAddress endpointAddress);
   public T CreateChannel( );
   //More Members
}
You need to provide the constructor of ChannelFactory<T> with the endpoint—either the endpoint name from the client config file, or the binding and address objects, or a ServiceEndpoint object. Next, use the CreateChannel( ) method to obtain a reference to the proxy and use its methods. Finally, close the proxy by either casting it to IDisposable and calling the Dispose( ) method or to ICommunicationObject and calling the Close( ) method:
ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>( );

IMyContract proxy1 = factory.CreateChannel( );
using(proxy1 as IDisposable)
{
   proxy1.MyMethod( );
}

IMyContract proxy2 = factory.CreateChannel( );
proxy2.MyMethod( );
ICommunicationObject channel = proxy2 as ICommunicationObject;
Debug.Assert(channel != null);
channel.Close( );
You can also use the shorthand static CreateChannel( )
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Reliability
WCF and other service-oriented technologies make a distinction between transport reliability and message reliability. Transport reliability (such as the one offered by TCP) offers point-to-point guaranteed delivery at the network packet level, as well as guarantees the order of the packets. Transport reliability is not resilient to dropping network connections and a variety of other communication problems.
Message reliability, as the name implies, deals with reliability at the message level independent of how many packets are required to deliver the message. Message reliability provides for end-to-end guaranteed delivery and order of messages, regardless of how many intermediaries are involved, and how many network hops are required to deliver the message from the client to the service. Message reliability is based on an industry standard for reliable message-based communication that maintains a session at the transport level. It offers retries in case of transport failures such as dropping a wireless connection; it automatically deals with congestion, message buffering, and flow control; and it can adjust the number of messages accordingly. Message reliability also deals with managing the connection itself via connection verification and cleanup when no longer needed.
In WCF, reliability is controlled and configured in the binding. A particular binding can support or not support reliable messaging, and if supported, it can be enabled or disabled. Which binding supports which reliability value is driven by the target scenario for that particular binding. Table 1-2 summarizes the relationship between binding, reliability, and ordered delivery and their respective default values.
Table 1-2: Reliability and binding
Name
Supports reliability
Default reliability
Supports ordered
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Service Contracts
The ServiceContract attribute presented in the previous chapter exposes an interface (or a class) as a service-oriented contract, allowing you to program in languages like C#, using constructs like interfaces, while exposing the constructs as WCF contracts and services. This chapter starts by discussing how to better bridge the gap between the two programming models by enabling operation overloading and contract inheritance. Next you will see a few simple yet powerful service contract design and factoring guidelines and techniques. The chapter ends by showing how to interact programmatically at run runtime with the metadata of the exposed contracts.
Programming languages such as C++ and C# support method overloading: defining two methods with the same name but with different parameters. For example, this is a valid C# interface definition:
interface ICalculator
{
   int Add(int arg1,int arg2);
   double Add(double arg1,double arg2);
}
However, operation overloading is invalid in the world of WSDL-based operations. Consequently, while the following contract definition compiles, it will throw an InvalidOperationException at the service host load time:
//Invalid contract definition:
[ServiceContract]
interface ICalculator
{
   [OperationContract]
   int Add(int arg1,int arg2);

   [OperationContract]
   double Add(double arg1,double arg2);
}
However, you can manually enable operation overloading. The trick is using the Name property of the OperationContract attribute to alias the operation:
[AttributeUsage(AttributeTargets.Method)]
public sealed class OperationContractAttribute : Attribute
{
   public string Name
   {get;set;}
   //More members
}
You need to alias the operation both on the service and on the client side. On the service side, provide a unique name for the overloaded operations, as shown in Example 2-1.
Example 2-1. Service-side operation overloading
[ServiceContract]
interface ICalculator
{
   [OperationContract(Name = "AddInt")]
   int Add(int arg1,int arg2);

   [OperationContract(
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Operation Overloading
Programming languages such as C++ and C# support method overloading: defining two methods with the same name but with different parameters. For example, this is a valid C# interface definition:
interface ICalculator
{
   int Add(int arg1,int arg2);
   double Add(double arg1,double arg2);
}
However, operation overloading is invalid in the world of WSDL-based operations. Consequently, while the following contract definition compiles, it will throw an InvalidOperationException at the service host load time:
//Invalid contract definition:
[ServiceContract]
interface ICalculator
{
   [OperationContract]
   int Add(int arg1,int arg2);

   [OperationContract]
   double Add(double arg1,double arg2);
}
However, you can manually enable operation overloading. The trick is using the Name property of the OperationContract attribute to alias the operation:
[AttributeUsage(AttributeTargets.Method)]
public sealed class OperationContractAttribute : Attribute
{
   public string Name
   {get;set;}
   //More members
}
You need to alias the operation both on the service and on the client side. On the service side, provide a unique name for the overloaded operations, as shown in Example 2-1.
Example 2-1. Service-side operation overloading
[ServiceContract]
interface ICalculator
{
   [OperationContract(Name = "AddInt")]
   int Add(int arg1,int arg2);

   [OperationContract(Name = "AddDouble")]
   double Add(double arg1,double arg2);
}
When the client imports the contract and generates the proxy, the imported operations will have the aliased names:
[ServiceContract]
public interface ICalculator
{
   [OperationContract]
   int AddInt(int arg1,int arg2);

   [OperationContract]
   double AddDouble(double arg1,double arg2);
}
public partial class CalculatorClient : ClientBase<ICalculator>,ICalculator
{
   public int AddInt(int arg1,int arg2)
   {
      return Channel.AddInt(arg1,arg2);
   }
   public double AddDouble(double arg1,double arg2)
   {
      return Channel.AddDouble(arg1,arg2);
   }
   //Rest of the proxy
}
The client can use the generated proxy and contract as is, but you can also rework those to provide overloading on the client side. Rename the methods on the imported contract and the proxy to the overloaded name, and make sure the proxy class makes calls on the internal proxy using the overloaded methods, such as:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Contract Inheritance
Service contract interfaces can derive from each other, enabling you to define a hierarchy of contracts. However, the ServiceContract attribute is not inheritable:
[AttributeUsage(Inherited = false,...)]
public sealed class ServiceContractAttribute : Attribute
{...}
Consequently, every level in the interface hierarchy must explicitly have the ServiceContract attribute, as shown in Example 2-3.
Example 2-3. Service-side contract hierarchy
[ServiceContract]
interface ISimpleCalculator
{
   [OperationContract]
   int Add(int arg1,int arg2);
}
[ServiceContract]
interface IScientificCalculator : ISimpleCalculator
{
   [OperationContract]
   int Multiply(int arg1,int arg2);
}
When it comes to implementing a contract hierarchy, a single service class can implement the entire hierarchy, just as with classic C# programming:
class MyCalculator : IScientificCalculator
{
   public int Add(int arg1,int arg2)
   {
      return arg1 + arg2;
   }
   public int Multiply(int arg1,int arg2)
   {
      return arg1 * arg2;
   }
}
The host can expose a single endpoint for the bottom most interface in the hierarchy:
<service name = "MyCalculator">
   <endpoint
      address  = "http://localhost:8001/MyCalculator/"
      binding  = "basicHttpBinding"
      contract = "IScientificCalculator"
   />
</service>
When the client imports the metadata of a service endpoint whose contract is part of an interface hierarchy, the resulting contract on the client side does not maintain the original hierarchy. Instead it will include a flattened hierarchy in the form of a single contract named after the endpoint's contract. The single contract will have a union of all the operations from all the interfaces leading down to it in the hierarchy, including itself. However, the imported interface definition will maintain, in the Action and ResponseAction properties of the OperationContract attribute, the name of the original contract that defined each operation:
[AttributeUsage(AttributeTargets.Method)]
public sealed class OperationContractAttribute : Attribute
{
   public string Action
   {get;set;}
   public string ReplyAction
   {get;set;}
   //More members
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Service Contracts Factoring and Design
Syntax aside, how do you go about designing service contracts? How do you know which operations to allocate to which service contract? How many operations should each contract have? Answering these questions has little to do with WCF and a lot to do with abstract service-oriented analysis and design. An in-depth discussion of how to decompose a system into services and how to discover contract methods is beyond the scope of this book. Nonetheless, this section offers a few pieces of advice to guide you in your service contracts design effort.
A service contract is a grouping of logically related operations. What constitutes "logically related" is usually domain-specific. You can think of service contracts as different facets of some entity. Once you have identified (after requirements analysis) all the operations the entity supports, you need to allocate them to contracts. This is called service contract factoring. When you factor a service contract, always think in terms of reusable elements. In a service-oriented application, the basic unit of reuse is the service contract. Would this particular contract factoring yield contracts that other entities in the system can reuse? What facets of the entity can logically be factored out and used by other entities?
As a concrete yet simple example, suppose you wish to model a dog service. The requirements are that the dog should be able to bark and fetch, that the dog should have a veterinary clinic registration number, and that you could vaccinate it. You can define the IDog service contract and have different kinds of services, such as the PoodleService and the GermanShepherdService implement the IDog contract:
[ServiceContract]
interface IDog
{
   [OperationContract]
   void Fetch( );

   [OperationContract]
   void Bark( );

   [OperationContract]
   long GetVetClinicNumber( );

   [OperationContract]
   void Vaccinate( );
}
class PoodleService : IDog
{...}
class GermanShepherdService : IDog
{...}
However, such a composition of the IDog service contract is not well factored. Even though all the operations are things a dog should support,
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Contract Queries
Sometimes the client needs to programmatically verify whether a particular endpoint (identified by its address) supports a particular contract. For example, imagine an application where the end user specifies or configures the application during setup (or even at runtime) to consume and interact with a service. If the service does not support the required contracts, the application should alert the user that an invalid address was specified, and ask for an alternative or a correct address. For example, the Credentials Manager application used in Chapter 10 has just such a feature: the user needs to provide it with the address of the security credentials service that manages accounts membership and roles. Credentials Manager only allows the user to select a valid address, after verifying the address supports the required service contracts.
In order to support such functionality, the application needs to retrieve the metadata of the service endpoints and see if at least one of the endpoints supports the requested contract. As explained in Chapter 1, the metadata is available in special metadata exchange endpoints that the service might support or over the HTTP-GET protocol. When you use HTTP-GET, the address of the metadata exchange is the HTTP-GET address (usually just the base address of the service suffixed by ?wsdl). To ease the task of parsing the returned metadata, WCF offers a few helper classes, available in the System.ServiceModel.Description namespaces, as shown in Example 2-7.
Example 2-7. Metadata processing supporting types
public enum MetadataExchangeClientMode
{
   MetadataExchange,
   HttpGet
}
class MetadataSet : ...
{...}
public class ServiceEndpointCollection : Collection<ServiceEndpoint>
{...}

public class MetadataExchangeClient
{
   public MetadataExchangeClient( );
   public MetadataExchangeClient(Binding mexBinding);
   public MetadataSet GetMetadata(Uri address,MetadataExchangeClientMode mode);
   //More members
}
public abstract class MetadataImporter
{
   public abstract ServiceEndpointCollection ImportAllEndpoints( );
   //More members
}
public class WsdlImporter : MetadataImporter
{
   public WsdlImporter(MetadataSet metadata);
   //More members
}
public class ServiceEndpoint
{
   public EndpointAddress Address
   {get;set;}
   public Binding Binding
   {get;set;}
   public ContractDescription Contract
   {get;}
   //More members
}
public class ContractDescription
{
   public string Name
   {get;set;}
   public string Namespace
   {get;set;}
   //More members
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Data Contracts
In the abstract, all that WCF provides for is the ability to host and expose native CLR types (interfaces and classes) as services, and the ability to consume services as native CLR interfaces and classes. WCF service operations accept and return CLR types such as integers and strings, and the WCF clients pass in and process returned CLR types. However, such CLR types are specific to .NET, of course. One of the core tenets of service-orientation is that services do not betray their implementation technology across the service boundary. As a result, any client, regardless of its own technology, can interact with the service. This obviously means that WCF cannot allow you to expose the CLR data types across the service boundary. What you need is a way of converting CLR types to and from a standard neutral representation. That representation is a simple XML-based schema or an infoset. In addition, the service needs a formal way for declaring how such conversion is to take place. This formal way is called a data contract, and it is the subject of this chapter. This first part of the chapter shows how data contracts enable type marshaling and conversions and how the infrastructure deals with class hierarchies and data contract versioning. The second part shows how to use various .NET types such as enumerations, delegates, data tables, and collections as data contracts.
The data contract is part of the contractual operations the service supports, just like the service contract is part of that contract. The data contract is published in the service metadata, which allows clients to convert the neutral, technology-agnostic representation to the client's native representation. Because objects and local references are CLR concepts, you cannot pass to and from a WCF service operation your CLR objects and references. Allowing you to do so would not just violate the core service-oriented principle discussed previously, but would also be impractical, since the object is comprised of both the state and the code manipulating it. There is no way of sending the code or the logic as part of a C# or Visual Basic method invocation, let alone marshaling it to another platform and technology. In fact, when passing an object (or a value type) as an operation parameter, all you really need to send is the state of that object, and you let the receiving side convert it back to its own native representation. Such an approach for passing state around is called
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Serialization
The data contract is part of the contractual operations the service supports, just like the service contract is part of that contract. The data contract is published in the service metadata, which allows clients to convert the neutral, technology-agnostic representation to the client's native representation. Because objects and local references are CLR concepts, you cannot pass to and from a WCF service operation your CLR objects and references. Allowing you to do so would not just violate the core service-oriented principle discussed previously, but would also be impractical, since the object is comprised of both the state and the code manipulating it. There is no way of sending the code or the logic as part of a C# or Visual Basic method invocation, let alone marshaling it to another platform and technology. In fact, when passing an object (or a value type) as an operation parameter, all you really need to send is the state of that object, and you let the receiving side convert it back to its own native representation. Such an approach for passing state around is called marshaling by value. The easiest way to perform marshaling by value is to rely on the built-in support most platforms (.NET included) offer for serialization. The approach is simple enough, as shown in Figure 3-1.
Figure 3-1: Serialization and deserialization during an operation call
On the client side, WCF will serialize the in-parameters from the CLR native representation to an XML infoset and bundle them in the outgoing message to the client. Once the message is received on the service side, WCF will deserialize it and convert the neutral XML infoset to the corresponding CLR representation before dispatching the call to the service. The service will then process the native CLR parameters. Once the service finishes executing the operation, WCF will serialize the out-parameters and the returned values into a neutral XML infoset, package them in the returned message, and post the returned message to the client. Finally, on the client, WCF will deserialize the returned values into native CLR types and return them to the client.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Data Contract Attributes
While the Serializable attribute is workable, it is inadequate for service-oriented interaction between clients and services. It denotes all members in the type as serializable and therefore part of the data schema for that type. It is much better to have an opt-in approach, where only members the contract developer wants to explicitly include in the data contract are included. The Serializable attribute forces the data type to be serializable in order to be used as a parameter in a contract operation, and does not offer clean separation between the serviceness aspect of the type (ability to use it as a WCF operation parameter) and the ability to serialize it. The attribute offers no support for aliasing type name or members, or for mapping a new type to a predefined data contract. The attribute operates directly on member fields, and completely bypasses any logical properties used to access those fields. It would be better to allow those properties to add their values when accessing the fields. Finally, there is no direct support for versioning because any versioning information is supposedly captured by the formatters. Consequently, it is difficult to deal with versioning over time.
Yet again, the solution is to come up with new WCF service-oriented opt-in attributes. The first of these attributes is the DataContractAttribute defined in the System.Runtime.Serialization namespace:
[AttributeUsage(AttributeTargets.Enum  |
                AttributeTargets.Struct|
                AttributeTargets.Class,
                Inherited = false)]
public sealed class DataContractAttribute : Attribute
{
   public string Name
   {get;set;}
   public string Namespace
   {get;set;}
}
Applying the DataContract attribute on a class or struct does not cause WCF to serialize any of its members:
[DataContract]
struct Contact
{
   //Will not be part of the data contract
   public string FirstName;
   public string LastName;
}
All the DataContract attribute does is merely opt-in the type, indicating that the type is willing to be marshaled by value. To serialize any of its members, you must apply the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Data Contract Hierarchy
Your data contract class may be the subclass of another data contract class. WCF requires that every level in the class hierarchy explicitly opt in for a given data contract, because the DataContract attribute is not inheritable:
[DataContract]
class Contact
{
   [DataMember]
   public string FirstName;

   [DataMember]
   public string LastName;
}
[DataContract]
class Customer : Contact
{
   [DataMember]
   public int OrderNumber;
}
Failing to designate every level in the class hierarchy as serializable or as a data contract will result in an InvalidDataContractException at the service load time. WCF lets you mix the Serializable and DataContract attribute in the class hierarchy:
[Serializable]
class Contact
{...}

[DataContract]
class Customer : Contact
{..}
But typically the Serializable attribute will be at the root of the class hierarchy, if at all, because new classes should use the DataContract attribute. When you export a data contract hierarchy, the metadata maintains the hierarchy, and all levels of the class hierarchy are exported when making use of the subclass in a service contract:
[ServiceContract]
interface IContactManager
{
   [OperationContract]
   void AddCustomer(Customer customer);//Contact is exported as well
   ...
}
While languages such as C# let you substitute a subclass for a base class, this is not the case with WCF operations. By default, you cannot use a subclass of a data contract class instead of its base class. Consider this service contract:
[ServiceContract]
interface IContactManager
{
   //Cannot accept Customer object here:
   [OperationContract]
   void AddContact(Contact contact);

   //Cannot return Customer objects here:
   [OperationContract]
   Contact[] GetContacts( );
}
Suppose the client defined the Customer class as well:
[DataContract]
class Customer : Contact
{
   [DataMember]
   public int OrderNumber;
}
While the following code compiles successfully, it fails at runtime:
Contact contact = new Customer( );
contact.FirstName = "Juval";
contact.LastName = "Lowy";

ContactManagerClient proxy = new ContactManagerClient( );
//Service call will fail:
proxy.AddContact(contact);
proxy.Close( );
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Data Contract Equivalence
Two data contracts are considered equivalent if they have the same wire representation. This can be the case when defining the same type (but not necessarily the same version of the type), or if the two data contracts refer to two different types with the same names for the contract and the members. Equivalent data contracts are interchangeable: WCF will let any service that was defined with one data contract operate on an equivalent data contract.
The most common way of defining an equivalent data contract is to use the Name property of the DataContract or DataMember attribute to map one data contract to another. In the case of the DataContract attribute, the Name property defaults to the type's name, so these two definitions are identical:
[DataContract]
struct Contact
{...}

[DataContract(Name = "Contact")]
struct Contact
{...}
In fact, the full name of the data contract always includes its namespace as well, but as you have seen, you can assign a different namespace. In the case of the DataMember attribute, the Name defaults to member name, so these two definitions are identical:
[DataMember]
public string FirstName;

[DataMember(Name = "FirstName")]
public string FirstName;
By assigning different names to the contract and the members you can generate an equivalent data contract from a different type.
For example, these two data contracts are equivalent:
[DataContract]
struct Contact
{
   [DataMember]
   public string FirstName;

   [DataMember]
   public string LastName;
}
[DataContract(Name = "Contact")]
struct Person
{
   [DataMember(Name = "FirstName")]
   public string Name;

   [DataMember(Name = "LastName")]
   public string Surname;
}
In addition to having identical names, the types of the data members have to match.
A class and a structure that support the same data contract are interchangeable.
Equivalent data contracts must serialize and deserialize their members in the same order. The default serialization order inside a type is simply alphabetical, and across class hierarchy the order is top-down. In case of a mismatch in the serialization order, the members will be initialized to their default values. For example, when serializing a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Versioning
Services should be decoupled as much as possible from their clients, especially when it comes to versioning and technologies. Any version of the client should be able to consume any version of the service, and should do so without resorting to version numbers, such as those in assemblies, because those are .NET-specific. When a service and a client share a data contract, an important objective is allowing the service and client to evolve their versions of the data contract separately. To allow such decoupling, WCF needs to enable both backward and forward compatibility, without even sharing types or version information. There are three main versioning scenarios:
  • New members
  • Missing members
  • Round tripping, where a new version is passed to and from an old version, requiring both backward and forward compatibility
By default, data contracts are version tolerant and will silently ignore incompatibilities.
The most common change done with data contracts is adding new members on one side and sending the new