Creating User-Defined Bindings

There are several ways to create bindings not provided by the system:

  • Create a custom binding, based on the CustomBinding class, which is a container that you fill with binding elements. The custom binding is then added to a service endpoint. You can create the custom binding either programmatically or in an application configuration file. To use a binding element from an application configuration file, the binding element must extend BindingElementExtensionElement. For more information about custom bindings, see Custom Bindings and CustomBinding.

  • You can create a class that derives from a standard binding. For example, you can derive a class from WSHttpBinding and override CreateBindingElements method to obtain the binding elements and insert a custom binding element or establish a particular value for security.

  • You can create a new Binding type to completely control the entire binding implementation.

The Order of Binding Elements

Each binding element represents a processing step when sending or receiving messages. At run time, binding elements create the channels and listeners necessary to build outgoing and incoming channel stacks.

There are three main types of binding elements: Protocol Binding Elements, Encoding Binding Elements and Transport Binding Elements.

Protocol Binding Elements – These elements represent higher-level processing steps that act on messages. Channels and listeners created by these binding elements can add, remove, or modify the message content. A given binding may have an arbitrary number of protocol binding elements, each inheriting from BindingElement. Windows Communication Foundation (WCF) includes several protocol binding elements, including the ReliableSessionBindingElement and the SymmetricSecurityBindingElement.

Encoding Binding Element – These elements represent transformations between a message and an encoding ready for transmission on the wire. Typical WCF bindings include exactly one encoding binding element. Examples of encoding binding elements include the MtomMessageEncodingBindingElement, the BinaryMessageEncodingBindingElement, and the TextMessageEncodingBindingElement. If an encoding binding element is not specified for a binding, a default encoding is used. The default is text when the transport is HTTP and binary otherwise.

Transport Binding Element – These elements represent the transmission of an encoding message on a transport protocol. Typical WCF bindings include exactly one transport binding element, which inherits from TransportBindingElement. Examples of transport binding elements include the TcpTransportBindingElement, the HttpTransportBindingElement, and the NamedPipeTransportBindingElement.

When creating new bindings, the order of the added binding elements is important. Always add binding elements in the following order:

Layer Options Required
Transaction Flow System.ServiceModel.Channels.TransactionFlowBindingElement No
Reliability System.ServiceModel.Channels.ReliableSessionBindingElement No
Security System.ServiceModel.Channels.SecurityBindingElement No
Composite Duplex System.ServiceModel.Channels.CompositeDuplexBindingElement No
Encoding Text, Binary, MTOM, Custom Yes*
Transport TCP, Named Pipes, HTTP, HTTPS, MSMQ, Custom Yes

*Because an encoding is required for each binding, if an encoding is not specified, WCF adds a default encoding for you. The default is Text/XML for the HTTP and HTTPS transports, and Binary otherwise.

Creating a new Binding Element

In addition to the types derived from BindingElement that are provided by WCF, you can create your own binding elements. This lets you customize the way the stack of bindings is created and the components that go in it by creating your own BindingElement that can be composed with the other system-provided types in the stack.

For example, if you implement a LoggingBindingElement that provides the ability to log the message to a database, you must place it above a transport channel in the channel stack. In this case, the application creates a custom binding that composed the LoggingBindingElement with TcpTransportBindingElement, as in the following example.

Binding customBinding = new CustomBinding(  
  new LoggingBindingElement(),
  new TcpTransportBindingElement()  
);  

How you write your new binding element depends on its exact functionality. One of the samples, Transport: UDP, provides a detailed description of how to implement one kind of binding element.

Creating a New Binding

A user-created binding element can be used in two ways. The previous section illustrates the first way: through a custom binding. A custom binding allows the user to create their own binding based on an arbitrary set of binding elements, including user-created ones.

If you use the binding in more than one application, create your own binding and extend the Binding. This avoids manually creating a custom binding every time you want to use it. A user-defined binding allows you to define the binding’s behavior and include user-defined binding elements. And it is pre-packaged: you do not have to rebuild the binding every time you use it.

At a minimum, a user-defined binding must implement the CreateBindingElements method and the Scheme property.

The CreateBindingElements method returns a new BindingElementCollection that contains the binding elements for the binding. The collection is ordered, and should contain the protocol binding elements first, followed by the encoding binding element, followed by the transport binding element. When using the WCF system-provided binding elements, you must follow the binding element ordering rules specified in Custom Bindings. This collection should never reference objects referenced within the user-defined binding class; consequently, binding authors must return a Clone() of the BindingElementCollection on each call to CreateBindingElements.

The Scheme property represents the URI scheme for the transport protocol in use on the binding. For example, the WSHttpBinding and the NetTcpBinding return "http" and "net.tcp" from their respective Scheme properties.

For a complete list of optional methods and properties for user-defined bindings, see Binding.

Example

This example implements profile binding in SampleProfileUdpBinding, which derives from Binding. The SampleProfileUdpBinding contains up to four binding elements within it: one user-created UdpTransportBindingElement; and three system-provided: TextMessageEncodingBindingElement, CompositeDuplexBindingElement, and ReliableSessionBindingElement.

public override BindingElementCollection CreateBindingElements()  
{
    BindingElementCollection bindingElements = new BindingElementCollection();  
    if (ReliableSessionEnabled)  
    {  
        bindingElements.Add(session);  
        bindingElements.Add(compositeDuplex);  
    }  
    bindingElements.Add(encoding);  
    bindingElements.Add(transport);  
    return bindingElements.Clone();  
}  

Security Restrictions with Duplex Contracts

Not all binding elements are compatible with each other. In particular, there are some restrictions on security binding elements when used with duplex contracts.

One-Shot Security

You can implement "one-shot" security, where all the necessary security credentials are sent in a single message, by setting the negotiateServiceCredential attribute of the <message> configuration element to false.

One-shot authentication does not work with duplex contracts.

For Request-Reply contracts, one-shot authentication works only if the binding stack below the security binding element supports creating IRequestChannel or IRequestSessionChannel instances.

For one-way contracts, one-shot authentication works if the binding stack below the security binding element supports creating IRequestChannel, IRequestSessionChannel, IOutputChannel or IOutputSessionChannel instances.

Cookie mode security context tokens cannot be used with duplex contracts.

For Request-Reply contracts, cookie-mode security context tokens work only if the binding stack below the security binding element supports creating IRequestChannel or IRequestSessionChannel instances.

For one-way contracts, cookie-mode security context tokens works if the binding stack below the security binding element supports creating IRequestChannel or IRequestSessionChannel instances.

Session-mode Security Context Tokens

Session mode SCT works for duplex contracts if the binding stack below the security binding element supports creating IDuplexChannel or IDuplexSessionChannel instances.

Session mode SCT works for Request-Reply contracts if the binding stack below the security binding element supports creating IDuplexChannel, IDuplexSessionChannel, IRequestChannel or IRequestSessionChannel, instances.

Session mode SCT works for 1-way contracts if the binding stack below the security binding element supports creating IDuplexChannel, IDuplexSessionChannel, IRequestChannel or IRequestSessionChannel instances.

Deriving from a Standard Binding

Instead of creating an entirely new binding class, it may be possible for you to extend one of the existing system-provided bindings. Much like the preceding case, you must override the CreateBindingElements method and the Scheme property.

See also