Windows Communication Foundation WCF is a framework for building and running service-oriented applications (see Service Oriented Architecture). WCF and its System.ServiceModel namespace that represents its primary programming interface, is the successor and unification of most distributed systems technologies used to build distributed applications
The current distributed systems technologies are .NET Remoting, Web Services, Web Service Enhancements (WSE), MSMQ, and Enterprise Services/COM+. WCF unifies all these into one programming model and you no longer have to make an exclusive explicit choice for one of these technologies. For example, with WCF you can build a Web Service with reliable communication that supports sessions and transaction flow and extend it to let you view the raw messages as they flow into the system.
Therefore, WCF offers a single programming model that unifies the features of .NET Remoting, MSMQ, Enterprise Services, Web Services and Web Service Enhancements
WCF is a set of APIs for creating systems that send messages between clients and services. These messages can be sent over the Intranet and the Internet using common transports such as TCP, HTTP, MSMQ, Web Services, etc. Messages can be sent securely and digitally signed for integrity. Simple message patterns such request/response and more complex patterns such as such as communication over two channels are supported.
Other major features include interoperability with existing Web Services and with system that implement Web Service Enhancements (collectively know as "WS-*" specifications). By adhering to these standards applications that use WCF can communicate with clients and services created on other non-Microsoft platforms.
The followings briefly explains most of the concepts and terms used in WCF:
Message: Self-contained packets of data that may consist
of several parts including header and body. All parts of a message can be
encrypted and digitally signed except for the header which must be in clear
text.
Service: A software module (EXE or DLL) that provides 1 to n
endpoints with each endpoint providing 1 to n
service operations.
Endpoint: A single interface that is used to establish
communications between clients and hosts. Each
endpoints has its own address that
is appended to the base address of the service, making it a unique entity. A WCF
service is a collection of endpoints.
Binding: A set of properties that define
how an endpoint
communicates with the outside world. At the very least, the binding defines the
transport (HTTP or TCP) that is necessary to communicate with the
endpoint. A
binding may also specify other details such as security or the
message pattern
used by the endpoint.
System-provided bindings: A collection of
bindings that are
optimized for certain scenarios. For example, WSHttpBinding is designed for interoperability with Web Services that
implement various WS-* specifications.
Service Contract: The contract defines the name of the
service, its namespace, and other global attributes. In practice, a contract
is defined by creating an interface (interface in
C#) and applying the the [ServiceContract]
attribute. See interface IMyBasicService in
example 1. The actual service code is the class that
implements this interface.
Operation Contract: Given that a
service contract
is defined by creating an interface and annotating it with
[ServiceContract], an operation contract is
a member method of that interface that defines the return type and parameters
of an operation. Such an interface method must be annotated with
[OperationContract]. See interface
IMyBasicService in example 1.
Data Contract: Data types used by a service must be
described in metadata to enable clients to interoperate with the service. The
descriptions of the data types are known as data contracts and the types
may be used in any message (parameters or return types).
Service operation: A method that is implemented and
exposed by a service for consumption by any client. If a
service contract is
defined by creating an interface, then a service operation is the class
that implements this interface. See class
MyBasicService in example 1
The method may or may not return a value, and may or may not take
any arguments. Note while a method invocation might appear as a single operation
on the client, it can result in sending multiple messages to the service. For
example, a method with two arguments called on a WCF client results in two
messages sent to the service.
Host: A host is an application (typically .exe) that is
used to control the lifetime of a service. A host can be a console, a Windows
Service, a Window Activation Service (WAS) and Internet Information Service
(IIS) among others. For IIS, you can set a virtual directory that contains the
service assemblies and configuration file. When a message is received, IIS
starts the service and control its lifetime. When a client (or clients) end(s) the session, IIS closes the application and releases it resources. See
class Program in example 1
which is hosted inside a console application.
Behaviour: A behaviour is a type (i.e.,
class) that augments the runtime functionality of
a service. Service behaviours are enabled by applying a [ServiceBehaviour]
attribute to a service class and setting properties to enable various
behaviours.
Behaviours are used to control various runtime
aspects of a service or endpoint. Behaviours are grouped according to scope:
Common behaviours affect all endpoints, service behaviours affect only
service-related aspects, and endpoint behaviours affect only endpoint-related
properties. For example, an endpoint behaviour may specify where and how to find
a security credential.
Instancing: A service has an instancing model which
controls how many instances of the service can run at one time. There are four
instancing models: single, per call, per session, and
shareable. The first two are similar in concepts to the Singleton and
Single Call SAOs in .NET Remoting. Instancing is a behaviour and and as such
it is specified as part of the [ServiceBehaviour]
attribute as follows: [ServiceBehavior(InstanceContextMode
= InstanceContextMode.PerCall)].
Client Application: A program that exchanges
messages with
one or more endpoints. The client application typically creates a
WCF Client
Object and then calling methods on this proxy object. See class
WCFClientApp in example 1.
Channel: This is the transport connection between a client
application and an endpoint in a service. A client uses a transport (TCP,
HTTP, etc.) and an address to construct a channel to a specific
endpoint.
WCF Client Object: This a
client-side construct that encapsulates service operations as methods, in
other words, a WCF Client Object is a proxy to the service methods. Note that
any application can host a WCF Client Object, even an application hosting a
service. Therefore, it is possible to create a service that includes and uses
proxies to other services (service aggregation - an important
concept of SOA). These proxies are typically generated using the
svcutil.exe command-line utility.
Metadata: data that is generated by the svcutil.exe command-line utility. This data includes:
The following illustrates the major components of the WCF architecture (Contracts, Service Runtime, Messaging and Activation & Hosting):
Data Contract: Describes every parameter that makes up every message that a service can create or consume. These message parameters are described by XSD allowing any system that understands XML to process these messages.
Message Contract: Defines specific message parts using SOAP protocols and allow fine-grained control over parts of the message.
Service Contract: Defined previously here.
Policy and Binding: Defined previously here.
The runtime layer contains behaviours that only occur during the actual operation of the service. For example, throttling controls how many messages are processed. Error behaviour determines what happens when an occur occurs. Metadata behaviour governs how and whether metadata is made available to the outside world. Instance behaviour was discussed previously here, and so on.
The messaging layer deals with the possible formats and message patterns of the data. For example, WS Security Channel is an implementation of the WS-Security specification enabling security at the message layer. The WS Reliable Messaging Channel guarantees message delivery. The encoders allow to determine whether the message should be sent as text, XML, or any of the other supported encodings. HTTP Channel and TCP Channel determine which transport protocol to use while MSMQ channel allows interoperation with MSMQ applications.
A service can be either self-hosted or hosted in the context of another application. A Service can run as an EXE, Windows Service, under COM+ or under IIS.
Recall that a WCF service is a program that exposes a collection of Endpoints. Each endpoint is a portal for communicating with the world. A client is a program that exchanges messages with one or more endpoints. A client may also expose endpoints to receive messages from a service in a duplex message exchange pattern. The following sections describe these fundamentals in more details.
'ABC' is the key to understanding how an endpoint is composed:
A stands for Address. Where is the service? EndpointAddress is the WCF class that represents an endpoint address.
B stands for Binding. How do I talk to the service including things like transport protocol, encoding and security requirements? Binding is the WCF class that represents a binding.
C stands for Contract. What does the service allow me to do? ContractDescription is the WCF class that represents a contract.
WCF represents an endpoint using ServiceEndpoint class which has an EndpointAddress, a Binding, and a ContractDescription, corresponding to the endpoint's Address, Binding, and Contract:
The components of a ServiceEndpoint are described below:
An EndpointAddress corresponds to 'where is the service?' An EndpointAddress is basically a URI, an identity and a collection of optional headers used to provide additional addressing information beyond the URI (i.e., differentiating between multiple endpoints with the same URI):
A Binding which describes how to interact with an endpoint, has a name, namespace and a collection of composable binding elements:
The Binding's Name and Namespace are used to uniquely identify the binding in the service's metadata. The collection of binding elements can be used to describe parts of how the endpoint communicates with the outside world. For example, consider the following collection of binding elements:
This collection of bindings indicates how to interact with the endpoint:
The TcpTransportBindingElement indicates that the endpoint will communicate with the outside world using TCP as the transport protocol.
The ReliableSessionBindingElement indicates that the endpoint will use reliable messaging to provide message delivery.
The SecurityBindingElement indicates that the endpoint will use SOAP message security.
The order and types of binding elements is important: The collection of binding elements is used to build a communication stack ordered according to the order of the binding elements in the binding collection. The last element added to the binding collection corresponds to the bottom component of the communication stack, while the first element added to the binding collection corresponds to the top component of the communication stack. Incoming messages flow through this stack from bottom to top (see figure above), while outgoing messages flow through this stack from top to bottom (see figure above).
Finally note that WCF provides a set of pre-defined bindings that can be used in the majority of scenarios instead of defining custom bindings.
A WCF contract is essentially a class with methods that defines what the endpoint does. A contract is similar to .NET Remoting's SAOs or CAOs. Each method is a simple message exchange. ContractDescription class is used to describe WCF contracts and their operations. Each contract (again represented by a ContractDescription class), has a corresponding OperationDescription that described aspects of the operation such as whether the operation is one-way or request/reply:
A duplex contract defines two logical sets of operations: A set that the Service exposes for the Client to call, and a set that the Client exposes for the Service to call. The programming model to define a duplex contract is to split each set in a separate type (i.e., class or interface) and annotate the contract that represents the service's operations with ServiceContractAttribute referencing the contract that defines the client (or callback) operations.
A ServiceBehaviour is a type that implements IServiceBehaviour and applies to services. Similarly a channel behaviour is a type that implements an IChannelBehaviour and applies to client channels. Behaviours are types that extend or modify Service or Client functionality. Behaviours are participate in the process of building a channel and can modify that channel based on user-specified settings.
A ServcieDescription is a structure that describes a WCF service including the Endpoints exposed by the service, the Behaviours applies to the service, and the type (i.e., class) that implements the service. A ServiceDescription class is used to create metadata, code/config and channels:
You can build this service description by hand, or more commonly, you can create it from a type annotated with certain WCF attributes. The code for this type can either be created by hand or generated from a WSDL document using a WCF tool called svcutil.exe.
Similarly on the client side, a ChannelDescription is a structure that describes a WCF's client that can communicate with a specific service endpoint:
Note that unlike ServiceDescription, a ChannelDescription contains only one ServiceEndpoint that represents the target Endpoint with which the client channel will communicate.
The WCF Runtime is the set of objects responsible for actually sending and receiving messages. This involves formatting messages, applying security, and transmitting and receiving messages using various protocols. The following explains the key concepts of the WCF runtime:
A WCF Message is the unit of data exchange between a client and an endpoint. A message is essentially an in-memory representation of a SOAP message InfoSet. Note that a WCF Message is not tied to text XML, rather depending on which encoding mechanism is used, a Message can be serialized using the binary formatter, text XML , or any other custom format.
There are two categories of channels: Transport channels and Protocol channels. Transport channels handle sending and receiving opaque octet streams using some form of transport protocol such as TCP, UDP or MSMQ. Protocol channels implement a SOAP-based protocol by processing and possibly modifying messages.
An EndpointListener is the run-time equivalent of a ServiceEndpoint. The EndpointAddress, Binding, and Contract of a ServiceEndpoint correspond to the EndpointListener's listening address, message filtering and dispatch, and channel stack, respectively. The EndpointListener contains the Channel stack that is responsible for sending and receiving messages.
The WCF Runtime is usually created behind the scenes by calling ServiceHost.Open. ServiceHost drives the creation of a ServiceDescription and populates ServiceDescription's ServiceEndpoint collection with Endpoints defined in code or config. ServiceHost then uses ServiceDescription to create the channel stack in the form of an EndpointListener object for each ServiceEndpoint in the ServiceDescription:
Similarly on the client side, the client runtime is created by ChannelFactory which is the client's equivalent of ServiceHost: ChannelFactory drives the creation of a ChannelDescription based on a Contract type, Binding, and EndpointAddress. It then uses this ChannelDescription to create the client's channel stack.
Unlike the Service runtime, the client runtime does not contain EndpointListeners because a client always initiates connection to the Service so there is no need to "listen" for incoming connections.
The following code shows a very basic example of a working minimal WCF application. The project layout is shown below in the solution explorer - BasicClient is a WCF client (Console application) that invokes the service implemented by BasicServiceImplementation (Class Library) which in turn is hosted by BasicHost (WCF Service Library):
BasicServiceImplementation.csproj
/*
The first step is to create a contract for the service that will be shared with
the outside world. Recall that a contract is essentially a class, similar to SAO or CAO in .NET
Remoting,
that defines what the service does. The easiest way to create a contract is by
implementing
as interface that is annotated with ServiceContract attribute. Methods of the
interface
would need to be annotated with OperatonContract attribute as shown below.
Implementing the contract is a simple matter of implementing the methods of the
interface.
The implementing class becomes the WCF Service class */
using System.ServiceModel;
[ServiceContract()]
public interface IMyBasicService
{
[OperationContract()]
string MyOperation1(string myValue);
}
public class MyBasicService : IMyBasicService
{
public string MyOperation1(string myValue)
{
return "Hello " + myValue;
}
}
BasicHost.csporj
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<!-- Services
are defined under this the <services> section. As assembly
can have any number of services, with
each service having its own <service>
configuration section -->
<services>
<!-- This section and its content define the service
endpoint (ABC) which
include
Address, Binding, and Contract. Note that Attribute name corresponds
to the fully-qualified name of the type implementing the
contract.
The Contract
and Binding are defined in an <endpoint> child element
while the
Address is defined in a <host> child element -->
<service name="Basics.MyBasicService">
<!-- endpoint defines the contract's ABS. The 'address' element defines an
address that
is relative to the address specified in the <host> element. If attribute
'address'
was empty, then the address in <host> must be the full address -->
<endpoint address="/MyBasicService" contract="Basics.IMyBasicService" binding="wsHttpBinding"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
/* The next step is to run
the service and this implies doing three things: configuring, hosting, and
opening the service.
A WCF service consists of a contract (defined
in BasicService project), and
configuration entries that specify behaviours and endpoints associated with
that implementation (see <system.serviceModel> in your application configuration
file).
To define a WCF service, the initialization code is embedded inside a managed
application (console application). We then add an endpoint for the service
(in this example via configuration entries). And finally we create an instance
of ServiceHost and open it to automatically create listeners and start
listening
for incoming messages from clients.*/
internal class MyServiceHost
{
internal static ServiceHost myServiceHost = null;
internal static void StartService()
{
myServiceHost = new ServiceHost(typeof(Basics.MyBasicService));
// Open myServiceHost
myServiceHost.Open();
// Output some debugging information
DisplayInfo( myServiceHost );
}
internal static void StopService()
{
//Call StopService from your shutdown logic (i.e. dispose method)
Trace.WriteLine(" Service state: " + myServiceHost.State.ToString());
if (myServiceHost.State != CommunicationState.Closed)
{
myServiceHost.Close();
Trace.WriteLine(" Service closed!");
}
}
internal static void DisplayInfo( ServiceHost host )
{
// Service description
ServiceDescription description = myServiceHost.Description;
Trace.WriteLine("ServiceType: " + description.ServiceType.FullName);
Trace.WriteLine("Behaviours count: " + description.Behaviors.Count);
if (description.Endpoints.Count > 0)
{
foreach (ServiceEndpoint endpoint in description.Endpoints)
{
Trace.WriteLine( "Address: " + endpoint.Address.ToString() );
}
}
else
{
Trace.WriteLine("ServiceEndpoints count: " + description.Endpoints.Count );
}
}
class Program
{
static void Main(string[] args)
{
MyServiceHost.StartService();
// The service can now be accessed until user presses <return> to terminate the
service
Console.WriteLine("The service is ready");
Console.WriteLine("Press <RETURN> to terminate the service");
Console.ReadLine();
// Terminate the service
MyServiceHost.StopService();
}
}
BaseClient.csporj
/* A WCF client application is a managed
application that uses a WCF client object
to communication with another application.
A WCF client object is an object that represents a WCF Service in a form that
the client
can use locally to communicate with the remote service. In other words, a WCF
client object
is a proxy to the remote service.
There are two types of WCF client objects:
1. Objects that extend ClientBase
2. Channel objects returned from a call to ChannelFactory.CreateChannel.
Because these objects
implement interfaces, they directly model the inputs and outputs of abstract
services in managed
form and are implemented dynamically by the WCF client runtime
*/
class WCFClientApp
{
static void Main(string[] args)
{
// Create a channel to connect to the remote contract
ChannelFactory<IMyBasicService> factory = new ChannelFactory<IMyBasicService>(
new WSHttpBinding(),
new EndpointAddress("http://localhost:8080/MyBasicService"));
IMyBasicService channel = factory.CreateChannel();
// Invoke methods on the contract
string strParam = "WCF";
Console.WriteLine("Sent parameter: " + strParam);
string strReturnValue = channel.MyOperation1(strParam);
Console.WriteLine("Received return value: " + strReturnValue);
// Terminate service when user pressesn any key
Console.WriteLine("Press <RETURN> to terminate the service");
Console.ReadLine();
factory.Close();
}
}
[ServiceContract()]
public interface IMyBasicService
{
[OperationContract()]
string MyOperation1(string myValue);
}
To run this application, start two instances of VS.NET 2005 and open the Basics solution (which contains the three projects mentioned earlier). In one instance of VS.NET set BasicHost as the startup project and press F5. In the other instnace of VS.NET set BasicClient as the startup project and press F5. You can now step through client and server code as you would debug any client-server application. Outputs from both projects are shown below:
This example is similar to the Example 1 except that SVCUTIL.EXE is used to generate the proxy used by the client. All projects remain the same except for BasicClient.csproj which is now replaced by BasicClientWithProxy.csproj:
Note that BasicClientWithProxy project contains the file schemas.microsoft.com.2003.10.Serialization.cs which was generated by the SVCUTIL.EXE tool as follows (the tool was executed in output directory of BasicHost. This directory contains the outputs from both BasicServiceImplementation and BasicHost projects):
svcutil.exe BasicServiceImplementation.dll
This exports the contract implemented in BasicServiceImplementation.dll
to WSDL and XSD files. These files contain the metadata of the contract..
.svcutil.exe *.wsdl *.xsd /lanugage:C#
This command - executed in the same directory as
BasicHost.exe - generates a proxy file from the WSDL and XSD files.
Note: svcutil also generated a .config file which I had to modify as below. The generated .config file contained a detailed wsHttpBinding which was not properly matched to the server-side binding (I had to modify it as follows):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address="http://localhost:8080/MyBasicService" contract="IMyBasicService"
binding="wsHttpBinding"/>
</client>
</system.serviceModel>
</configuration>
class Program
{
static void Main(string[] args)
{
// Create an
instance of the proxy
MyBasicServiceClient proxy =
new MyBasicServiceClient();
string strReturnValue =
proxy.MyOperation1("yazan");
Console.WriteLine("Received return
value: " + strReturnValue);
// Terminate service
when user presses any key
Console.WriteLine("Press
<RETURN> to terminate the service");
Console.ReadLine();
}
}