Sometimes before WCF was, of course, possible for software running on different machines to communicate. Over the lifetime of Windows there have been many technologies to achieve this: sockets, DCOM, MSMQ, .NET Remoting, ASMX Web Services and more. The problem is all of these have different APIs and different levels of capability. The goal of WCF was to provide a unified API for communication and to be able to provide a common level of service irrespective of the underlying transport.
To understand the structure of WCF and why it looks the way it does useful starting point are the four tenets of service orientation. This is not because they are the one true definition of service orientation but because they came from the team that wrote WCF and, therefore, give an insight to the thinking behind the architecture of WCF. Fundamentally the internals of a service should not be visible to software consuming that service and interaction between systems is based on passing platform independent messages.
There are three core concepts at play whenever you use WCF: messages, channels and encoders.
Message is a first class construct in WCF and are modeled on SOAP messages. In other words they have a payload known as the body and an extensible collection of contextual headers independent of the transport. They also support a specific header called the action header which is defined in the WS-Addressing specification. The action identifies the intent (purpose) of the message. Messages are represented by the System.ServiceModel.Channels.Message class. How messages are passed between two parties depends on the Message Exchange Pattern. One way messaging means messages are passed on one direction only. Request/Response means that there is a matching response message for each request message. Duplex means that messages are passed freely in both directions without any required causality between them. WCF supports all three of these patterns out of the box.
There are two types of channels in WCF: transport and protocol. Transport channels are probably the most obvious: they move bytes from one place to another using some transport protocol. WCF, as of 4.5, ships with the following transports: TCP, HTTP, MSMQ, Named Pipes, UDP and WebSockets. It is, however, an extensible model and, for example, there is an RabbitMQ AMQP channel. Protocol channels are designed to layer in functionality not supported by the transport, for example, transaction flow of HTTP. The three core protocol channels that come with WCF are security, transaction flow and reliable messaging. They are implementations of Web Service specification such as WS-Security, WS-AtomicTransaction and WS-ReliableMessaging and pass any required information to-and-fro using the message’s Headers collection.
Messages are objects and transport channels move bytes. Something has to translate between those two worlds and that something is called an encoder. The encoder controls the format of a message on the wire. WCF comes with four encoders: Text, Binary, MTOM and POX. The Text encoder puts textual XML SOAP messages on the wire. The Binary encoder put a binary format of the SOAP message on the wire – this binary format is WCF specific and is not designed to be interoperable with other platforms. The MTOM encoder implements the MTOM specification and is a way to transport binary payloads over SOAP without base 64 encoding them. The POX (Plain Old XML) encoder strips of the SOAP pieces and just places the body of the message on the wire and, as such, isn’t limited to XML.
Protocol channels, encoders and transport channels are composed in a channel stack controlling how messages are passed between a sender and receiver.
Programming at the channel layer, however, is relatively heavy lifting and so, generally, we work at a higher level of abstraction that takes care of much of the inherent complexity. This abstraction sits on top of the channel layer and is called the Service Model Layer. With the service model layer there are only two things we have to build (we can build more if we choose to), the code that consumes the service functionality and the implementation of that functionality. All of the plumbing can be automated.
The service model layer has two concepts: endpoints and behaviors. Endpoints are those things that are agreed between the consumer and the service. Behaviors are local functionality that is not visible to the other side of the communication (e.g. how requests are mapped to threads).
You will often hear people talk about the ABCs of WCF. This is because the three component parts of an endpoint are Address, Binding and Contract.
This defines what functionality an endpoint supports: the operations and the messages they expect and may return. In WCF contracts are defined by using the[ServiceContract] and [OperationContract] attributes on interfaces or classes. Interfaces are commonly used as it allows a single service to implement many contracts.
Bindings specify the “how” of the communication: what transport protocol; how security is configured; what the messages look like on the wire, etc. In other words it defines what the channel layer looks like. There are a number of standard bindings modeling common scenarios and you can also define custom ones if you have other requirements. You can find a list of the standard bindings in WCF 4.5 here.
The address of the endpoint is where the service is listening and where the consumer will send messages. Address structure is determines by the transport protocol being used, for example HTTP based addresses start with http:// and have a machine name and potentially a port number in the address whereas MSMQ address start with net.msmq:// and contain the machine and queue name.
In the service model layer, a service is simply a class that implements one or more contracts. However, something must actively start listening for incoming messages. TheServiceHost class is responsible for instantiating the set of objects that listen at the address and dispatch the messages as method calls to the service implementation. You can either create the ServiceHost instance yourself and call Open on it (known as self hosting) or you can get the Windows Process Activation Service to do this (formally known as WAS hosting). WAS hosting is also commonly referred to as IIS hosting as the service is configured via IIS manager and the ASP.NET infrastructure.
Clients use proxy objects to make calls to services. These can be obtained in one of two ways: shared assembly and metadata.
Remember that the client must have the same endpoint definition as the service. In that case where does the client’s view of the contract come from? sharing an assembly between client and service gives both the definition of the contract. Then, using the same binding and address, the client creates an instance of the ChannelFactory<T> class (where T is the contract) and then calls CreateChannel to create the proxy.
Using a shared assembly works fine when it is reasonable for the service and client to share code but cannot be used if the service and client are different technologies and may want to be avoided if the client and service are maintained by unrelated teams. In these situations we can use metadata in the form of WSDL or WS-MetadataExchange to provide the client with a description of the endpoint which tools (Add Service Reference in Visual Studio and svcutil.exe from the command line) can consume and build the necessary code and configuration to invoke the service. Metadata is not turned on by default and must be enabled using the ServiceMetadataBehavior behavior in the service.
That then is a broad brush for how WCF hangs together. There are many other factors that need to be considered when building services but the raw plumbing of network communication isn’t something with which service developers need to get involved. Of course, there is nothing to stop developers getting involved at many of the extensibility points of WCF but fortunately that is not a requirement to get clients and services talking to each other