WCF at large: distributed systems
WCF is a solftware development kit (SDK) for developing and deploying services on Windows and was first released as part of .NET v3.0. Firstly, let's review what a service is. A service is a unit of functionality exposed to the world. It is basically the next logical step of evolution in regards from functions to objects to components to services. An SOA, or service-oriented application or architecture is by definition that every component of a system should be a service, and the system should be composed of several loosely-coupled services, that is, several services that are each independent of each other and the modification of one would not affect the others. A system here is referred to as a single unit of a program that serves a business process. The services can be local or remote and can be deployed by different organizations using different technologies.
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, used to communicate with the service. In WCF, all services expose contracts. The contract is a platform-neutral and standard way of describing what the service does. WCF defines four different types of contracts: Service contracts, Data contracts, Fault contracts and Message contracts. In WCF, there are multiple aspects of communication with any given service, and there are many possible communication patterns. WCF groups together sets of communication aspects in bindings. A binding is merely a consistent, canned set of choices regarding the transport protocol, message encoding, communication pattern, reliability, security, transaction propagation and interoperability.
The client of a service is the party consuming its functionality. It can be a Windows Console, Windows Form, ASP.NET page, WPF, etc. The client communicate by sending and receiving messages. Between WCF clients and services, interaction is done with SOAP (Simple Object Access Protocol) which is an RPC protocol based on XML and which can be used to authorize an object to invoke a method of an object physically located on another server. With WCF, the client never interacts directly with a service. Instead, it uses a proxy as an intermediate to forward calls to the service.
A first WCF example
Let's start by creating a simple program using Visual Studio 2008 to demonstrate how WCF works. First, let's create a new project of the Visual C# type, we will select WCF for creating a WCF service class library. We will name the project AMTServiceLibrary, because we are going to create a solution based on the AMT train network in the Montreal area.
Now, doing this will create a skeleton WCF service library. We will erase the files generated by Visual Studio so that we can create our own implementation to understand this process a little better.
OK. Now that these two classes are deleted, we are going to create a new class within this project. This class will be used to contain the data that needs to be transmitted between the client and the service.
We will create an Id, Origin, Destination, Submitter, Comments and TimeSubmitted fields to this class. In order to be able to use these fields in the WCF contract, we need to annotate this class with the [DataContract] attribute. A Service contract describe which operations the client can perform on the service. The DataContract attribute is defined in the System.Runtime.Serialization namespace. Each and every field that was created must be preceded by the [DataMember] attribute if we want them to be included within this Data contract.
Now we have a fully configured WCF Data Contract that we will be able to use withing WCF Service Contracts. To do this, we are going to add another class, in fact, this is not a class but an interface. We will call it ITrainService.
Now, here we have defined three methods that will be implemented in the corresponding TrainService class. The SubmitTrain() method will be used to create a new train, the GetTrains() method will be used to obtain a list of all trains from the service that have been created. Finally, the RemoveTrain() method will be used to remove a train from the list using it's id. This time, in order to make this a WCF Service Contract, we will need to include another namespace in this class which we will do by adding "using System.ServiceModel". This way, we can annotate our class with the [ServiceContract] attribute. Only interfaces or classes decorated with this attribute will be considered WCF contracts. We now have to annotate every method that we wish to include in our Service Contract with the [OperationContract] attribute. There are some restrictions as to what can be decorated with the [OperationContract] attribute, but we will not go into this in detail.
Now it's time to implement our contract onto our service. To do this, let's create another class and name it TrainService.cs
We have to make this class inherit the interface that we have just created previously and implement the methods that were initially defined. Now we see something new here, the [ServiceBehavior] annotation. WCF defines to types of declarative service-side behaviors, governed by two corresponding attributes. In the ServiceBehaviorAttribute you can set the InstanceContextMode of the service. This property defines how new service objects are created. The option we will using in this project is "Single" or Singleton: Only one InstanceContext object is used for all incoming calls and is not recycled subsequent to the calls. If a service object does not exist, one is created.
In this implementation, we will have a new train added to a list of trains. Each new train will be attributed a new id, in this case a Guid (Globally unique identifier) that will be used to identify each train. The GetTrains() method will be used to obtain the list of trains and the RemoveTrain() method will go through the list and find the train by it's ID to remove it.
Our project is now complete, we will need to define the 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 three-way 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.
This screen is obtained by right-clicking on the App.config file in the Solution Explorer. The first Endpoint here has to be associated with the AMTServiceLibrary.ITrainService which is a .dll in the /bin/Debug folder. The second Endpoint is set to IMetadataExchange, also known as MEX. The MEX endpoint supports an industry standard for exchanging metadata, represented in WCF by the IMetadataExchange interface.
Now that this is done, we can go ahead and build and run the project. What happens when we run a WCF Service Library project, the WCF Service Host will be launched as well as the WCF Test Client. The test client will communicate with the WCF host and will access the data from our service.
From here, we can define all the fields of our train using the SubmitTrain method of the ITrainService. After invoking these fields, we obtain a NullObject in response, which is normal since the method returns void.
After adding a couple of trains in this way, we can now obtain a list of trains by using the GetTrains() method:
Now, we can even try to remove a train by copy and pasting the Id using the RemoveTrain() method.
After doing this, we can now observe that we have one train that has been removed from our list by invoking the GetTrains() method once more.
- Programming WCF Services 3rd edition, O'Reilly
- Pluralsight screencasts on youtube