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.
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.dllin the System.ServiceModelnamespace.
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.
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.
Services’ Execution Boundaries
With WCF, the client never interacts with the service directly, even when dealing with a local, in-memory service. Instead, the client always uses a proxy to forward the call to the service. The proxy exposes the same operations as the service, plus some proxy-management methods.
WCF allows the client to communicate with the service across all execution boundaries. On the same machine (see Figure 1-2), the client can consume services in the same app domain, across app domains in the same process, or across processes.
Figure 1-2. Same-machine communication using WCF
Across machine boundaries (Figure 1-3), the client can interact with services in its intranet or across the Internet.
WCF and location transparency
Services
In the past, distributed computing technologies such as DCOM or .NET Remoting aspired to provide the same programming model to the client whether the object was local or remote. In the case of a local call, the client used a direct reference, and when
Figure 1-3.Cross-machine communication using WCF
dealing with a remote object, the client used a proxy. The problem with this approach of trying to take the local programming model and make it the remote programming model is that there is much more to a remote call than an object with a wire. Complex issues such as life cycle management, reliability, state management, scalability, and security raised their heads, making the remote programming model significantly more complex, all because it tried to be what it is not—a local object. WCF also strives to provide the client with the same programming model regardless of the location of the service. However, the WCF approach is the exact opposite: it takes the remote programming model of instantiating and using a proxy and uses it even in the most local case. Because all interactions are done via a proxy, requiring the same configuration and hosting, WCF maintains the same programming model for the local and remote cases; thus it not only enables you to switch locations without affecting the client, but also significantly simplifies the application programming model.
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 schemaused 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 URIis 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)
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 calledMyServiceis waiting for my calls.”
TCP Addresses
TCP addresses use net.tcpfor 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:
TCP-based addresses are used throughout this book.
You can configure TCP-based addresses from different hosts to share a port.
HTTP Addresses
HTTP addresses usehttpfor transport, and can also usehttpsfor secure transport. You typically use HTTP addresses with outward-facing Internet-based services, and can specify a port such as:
http://localhost:8001
When the port number is unspecified, it defaults to 80. Similar to TCP addresses, two HTTP addresses from the same host can share a port, even on the same machine.
HTTP-based addresses are also used throughout this book.
IPC Addresses
IPC addresses usenet.pipefor transport, to indicate the use of the Windows named pipe mechanism. In WCF, services that use named pipes can only accept calls from the same machine. Consequently, you must specify either the explicit local machine name orlocalhostfor the machine name, followed by a unique string for the pipe name:
net.pipe://localhost/MyPipe
You can only open a named pipe once per machine, and therefore it is not possible for two named pipe addresses to share a pipe name on the same machine.
IPC-based addresses are used throughout this book.
MSMQ Addresses
MSMQ addresses use net.msmqfor transport, to indicate the use of the Microsoft Message Queue (MSMQ). You must specify the queue name. When you’re dealing with private queues, you must specify the queue type, but that can be omitted for public queues:
Peer network addresses use net.p2pfor transport, to indicate the use of the Windows peer network transport. You must specify the peer network name as well as a unique path and port. Using and configuring peer networks is beyond the scope of this book, and you will see very little mention of peer networks in subsequent chapters.
In WCF, all services expose contracts. The contractis 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 asintandstring, 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 Service Contract
The ServiceContractAttributeis 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
//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"; } }
TheServiceContractattribute maps a CLR interface (or inferred interface, as you will see later on) to a technology-neutral service contract. TheServiceContractattribute exposes a CLR interface (or a class) as a WCF contract, independently of that type’s visibility. The type visibility has no bearing on WCF, because visibility is a CLR concept. Applying theServiceContractattribute on an internal interface exposes that interface as a public service contract, ready to be consumed across the service boundary. Without theServiceContractattribute, the interface is not visible to WCF clients, in line with the service-oriented tenet that service boundaries are explicit. To enforce that, all contracts must explicitly opt in: only interfaces (or classes) decorated with theServiceContractattribute will be considered as WCF contracts. Other types will not.
In addition, none of the members of the type will ever be part of the contract when using theServiceContractattribute. You must explicitly indicate to WCF which methods to expose as part of the WCF contract using theOperationContractAttribute, defined as:
[AttributeUsage(AttributeTargets.Method)] public sealed class OperationContractAttribute : Attribute {
public string Name {get;set;} //More members }
You can only apply theOperationContractattribute on methods, but not on properties, indexers, or events, which are CLR concepts. WCF only understands operations—logical functions—and theOperationContractattribute exposes a contract method as a logical operation to perform as part of the service contract. Other methods on the interface (or class) that do not have theOperationContractattribute will not be part of the contract. This enforces the explicit service boundary and maintains an explicit opt-in model for the operations themselves. In addition, a contract operation cannot use object references as parameters—only primitive types or data contracts are allowed.
WCF lets you apply the ServiceContract attribute on an interface or on a class. When you apply it on an interface, some class needs to implement the interface. In general, you use plain C# or VB to implement the interface, and nothing in the service class code pertains to it being a WCF service:
class MyService : IMyContract,IMyOtherContract { public string MyMethod() {...} public void MyOtherMethod() {...} }
There are, however, a few implementation constraints on the service implementation class. You should avoid parameterized constructors because only the default constructor will ever be used by WCF. Also, although the class can use internal properties, indexers, and static members, no WCF client will ever be able to access them.
WCF also lets you apply theServiceContractattribute directly on the service class, without ever defining a separate contract first:
Under the covers, WCF will infer the contract definition. You can apply theOperationContract attribute on any method of the class, be it private or public.
Avoid using theServiceContractattribute directly on the service class. Always define a separate contract, so that you can use it in other contexts.
Names and namespaces
You can and should define a namespace for your contract. The contract namespace serves the same purpose in WCF as it does in .NET programming: to scope a type of contract and reduce the overall chance for a collision. You use the Namespaceproperty of theServiceContractattribute to provide a namespace:
Unspecified, the contract namespace defaults to http://tempuri.org. For outward-facing services you would typically use your company’s URL, and for intranet services you can use any meaningful unique name, such asMyApplication.
By default, the exposed name of the contract will be the name of the interface used. However, you could use an alias for a contract to expose a different name to the clients in the metadata using theNameproperty of theServiceContractattribute:
In similar manner, the name of the publicly exposed operation defaults to the method name, but you can use theNameproperty of theOperationContractattribute to alias it to a different publicly exposed name: