Adapter as a WCF Binding - In Depth
WCF LOB Adapter SDK surfaces an adapter as a custom WCF Binding. A WCF Binding corresponds to the “How” of the WCF Message transfer from one Endpoint to another Endpoint. It produces a set of binding elements that correspond to particular design settings and describe how the endpoint communicates. The WCF Binding roughly equals Channel Stack and each binding element is a rough equivalent to one channel in the Channel Stack. An example of a WCF Binding is BasicHttpBinding that is suitable for Basic Profile Web Services.
Read more about WCF Bindings in depth here.
A binding supports various channel shapes and message exchange patterns.
The “outbound / send” binding is used to build a ChannelFactory, which in turn builds a channel stack and returns a reference to the top channel in the stack. The application can then use this channel to send messages. The “inbound / receive” binding is used to build a IChannelListener, which listens for incoming messages. The IChannelListener provides messages to the listening application by creating channel stacks and handing the application reference to the top channel. The application then uses this channel to receive incoming messages. The following table shows key interfaces that a developer is expected to implement to support inbound/outbound WCF bindings – either created using WCF LOB Adapter SDK or WCF Channel Model.
|
|
WCF LOB Adapter SDK |
WCF Channel Model |
|
Outbound |
IOutboundHandler
|
IRequestChannel / IRequestSessionChannel
IOutputChannel / IRequestOutputChannel |
|
Inbound |
IInboundHandler |
IReplyChannel / IReplySessionChannel
IInputChannel / IInputSessionChannel |
|
Duplex |
Not Supported |
IDuplexChannel / IDuplexSessionChannel |
IMPORTANT: Irrespective of how the binding is developed, WCF clients access these bindings in the same way – configuration or code.
The developer is working with a WCF Message when either creating a custom channel or developing an adapter using the WCF LOB Adapter SDK. A WCF Message is represented by an envelope with headers and a body. The header section consists of properties independent of transport such as addressing, security and reliable messaging. The body contains the payload. The rules for reading and writing the body and the headers are different: for example, the headers are always buffered in memory and may be accessed in any order any number of times, while the body may be read only once and may be streamed. WCF Message information model is closely aligned with SOAP. Normally, when using SOAP, the Message body is mapped to the SOAP body and the Message headers are mapped to the SOAP headers.
If you are writing an adapter using WCF LOB Adapter SDK or writing custom channels, you should become intimately familiar with System.ServiceModel.Channels.Message class. Here are a few useful links:
· Using the message class
· Service Station: WCF Messaging Fundamentals
Consider a WCF Service with the following endpoint information and interface. I used this sample implementation from WCF samples in path /basic/client/TypedClient.
· Contract = ICalculator
· Binding = BasicHttpBinding
· Address = http://sonua/servicemodelsamples/TypedClient/service.svc
· ServiceHost = IIS
using System;
using System.ServiceModel;
namespace Microsoft.ServiceModel.Samples
{
// Define a service contract.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
[OperationContract]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
// Service class which implements the service contract.
public class CalculatorService : ICalculator
{
. . .
}
}
Once the service is hosted in IIS, the WCF client can generate a proxy using Svcutil.Exe or [ASR]. The client application can use this proxy to communicate with the service endpoint. The app.config on the client side defines the following client endpoint.
<configuration>
<system.serviceModel>
<client>
<endpoint name=""
address="http://localhost/servicemodelsamples/TypedClient/service.svc"
binding="basicHttpBinding"
contract="Microsoft.ServiceModel.Samples.ICalculator" />
</client>
</system.serviceModel>
</configuration>
Here is a portion of the client program –
using System;
using System.ServiceModel.Channels;
using System.ServiceModel;
namespace Microsoft.ServiceModel.Samples
{
//The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
//Client implementation code.
class Client
{
static void Main()
{
// Create a client
CalculatorClient client = new CalculatorClient("CustomBinding");
// Call the Add service operation.
double value1 = 100.00D;
double value2 = 15.99D;
double result = client.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
// Call the Subtract service operation.
. . .
}
}
The following figure shows how the message flows over the WCF bindings from client to the service, where
· Contract = ICalculator
· User Code = Client
· Typed Proxy = CalculatorClient
· Service = CalculatorService

Here is the WCF message that flows between the client and the service. I captured the WCF Request Message and WCF Response Message by enabling Message Logging. There are many other ways to “peek” at the WCF message going from client endpoint to service endpoint and vice-versa.
WCF Request Message
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://Microsoft.ServiceModel.Samples/ICalculator/Add</a:Action>
<a:MessageID>urn:uuid:cf15e5e2-03fd-4c54-9ead-c859ec56c91d</a:MessageID>
<ActivityId CorrelationId="73c930d3-6585-4a60-95a5-f7d640ca2c67" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</s:Header>
<s:Body>
<Add xmlns="http://Microsoft.ServiceModel.Samples">
<n1>5</n1>
<n2>7</n2>
</Add>
</s:Body>
</s:Envelope>
WCF Response Message
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1" u:Id="_2" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse</a:Action>
<a:RelatesTo u:Id="_3" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">urn:uuid:ba888253-b832-4ce6-92a4-0b8a8424371e</a:RelatesTo>
</s:Header>
<s:Body u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<AddResponse xmlns="http://Microsoft.ServiceModel.Samples">
<AddResult>12</AddResult>
</AddResponse>
</s:Body>
</s:Envelope>
Replace the BasicHttpBinding with a custom WCF binding creating using WCF LOB Adapter SDK
Let’s replace the “basicHttpBinding” to another WCF custom binding. I will make this change in the configuration file by adding another client endpoint that uses a binding called “calcBinding”. This binding will write the WCF request message (entire SOAP envelope) to a file and read the pre-canned responses from another file. For simplicity sake, this binding doesn’t do any processing such as really adding two numbers.
<configuration>
<system.serviceModel>
<client>
<endpoint name="CustomCalcBinding"
address="calc:/"
binding="calcBinding"
contract="Microsoft.ServiceModel.Samples.ICalculator" />
<endpoint name=""
address="http://localhost/servicemodelsamples/TypedClient/Service.svc"
binding="wsHttpBinding"
contract="Microsoft.ServiceModel.Samples.ICalculator" />
</client>
</system.serviceModel>
</configuration>
In the client program, you can pass the configuration information to the proxy
CalculatorClient client = new CalculatorClient("CustomCalcBinding");
Then run the client program. This time it will flow through the custom binding as shown in the diagram below and get the responses from the file system.

You can use WCF Channel Model to create the custom binding. For this example, I have used WCF LOB Adapter SDK to create this binding. Here is a step-by-step walkthrough:
1) Use the WCF LOB Adapter Code Generation Wizard to generate the classes needed to surface the code as a WCF Binding
a. Click on File > New > Project > Visual C# > WCF LOB Adapter
b. Enter “Calculator” as the name of the adapter
c. Use “calc” as the scheme and “Microsoft.Samples.Adapters” for project namespace. Click on Next.
d. Select Synchronous Outbound. Ignore the other message flow patterns and metadata options. Click on Next.
e. Click Next on Adapter Properties page.
f. Click Next on Connection Properties page.
g. Click on Finish
2) The following classes will be generated:
a. Calculator (derives from Adapter which in turn derives from TransportBindingElement)
b. CalculatorBinding (derives from AdapterBinding which in turn derives from Binding)
c. CalculatorBindingCollectionElement (derives from StandardBindingCollectionElement)
d. CalculatorBindingElement (derives from StandardBindingElement)
e. CalculatorBindingElementExtensionElement (derives from BindingElementExtensionElement)
f. CalculatorConnection
g. CalculatorConnectionFactory
h. CalcualtorConnectionUri
i. CalculatorHandlerBase
j. CalculatorOutboundHandler
k. CalculatorTrace
3) Sign and build the project
4) GAC the assembly
5) Register the binding in machine.config (alternatively, you can also put this within app.config of your client)
<system.serviceModel>
<extensions>
<bindingElementExtensions>
<add name="calcTransport" type="Microsoft.Samples.Adapters.CalculatorBindingElementExtensionElement, Calculator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7727b35e1da7555"/>
</bindingElementExtensions>
<bindingExtensions>
<add name="calcBinding" type="Microsoft.Samples.Adapters.CalculatorBindingCollectionElement, Calculator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7727b35e1da7555"/>
</bindingExtensions>
</extensions>
<client>
<endpoint binding="calcBinding" contract="IMetdataExchange" name="calc"/>
</client>
</system.serviceModel>
6) Implement the CalculatorConnection, CalculatorConnectionUri and CalculatorOutboundHandler class
In the connection-derived class, remove the not-implemented exceptions.
#region Using Directives
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Microsoft.ServiceModel.Channels.Common;
#endregion
namespace Microsoft.Samples.Adapters
{
public class CalculatorConnection : IConnection