O'Reilly logo

Programming WCF Services by Juval Lowy

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Reliability

WCF and other service-oriented technologies make a distinction between transport reliability and message reliability. Transport reliability (such as the one offered by TCP) offers point-to-point guaranteed delivery at the network packet level, as well as guarantees the order of the packets. Transport reliability is not resilient to dropping network connections and a variety of other communication problems.

Message reliability, as the name implies, deals with reliability at the message level independent of how many packets are required to deliver the message. Message reliability provides for end-to-end guaranteed delivery and order of messages, regardless of how many intermediaries are involved, and how many network hops are required to deliver the message from the client to the service. Message reliability is based on an industry standard for reliable message-based communication that maintains a session at the transport level. It offers retries in case of transport failures such as dropping a wireless connection; it automatically deals with congestion, message buffering, and flow control; and it can adjust the number of messages accordingly. Message reliability also deals with managing the connection itself via connection verification and cleanup when no longer needed.

Binding and Reliability

In WCF, reliability is controlled and configured in the binding. A particular binding can support or not support reliable messaging, and if supported, it can be enabled or disabled. Which binding supports which reliability value is driven by the target scenario for that particular binding. Table 1-2 summarizes the relationship between binding, reliability, and ordered delivery and their respective default values.

Table 1-2. Reliability and binding

Name

Supports reliability

Default reliability

Supports ordered

Default ordered

BasicHttpBinding

No

N/A

No

N/A

NetTcpBinding

Yes

Off

Yes

On

NetPeerTcpBinding

No

N/A

No

N/A

NetNamedPipeBinding

No

N/A (On)

Yes

N/A (On)

WSHttpBinding

Yes

Off

Yes

On

WSFederationHttpBinding

Yes

Off

Yes

On

WSDualHttpBinding

Yes

On

Yes

On

NetMsmqBinding

No

N/A

No

N/A

MsmqIntegrationBinding

No

N/A

No

N/A

Reliability is not supported by the BasicHttpBinding, NetPeerTcpBinding, and the two MSMQ bindings, NetMsmqBinding and MsmqIntegrationBinding. The reason is that the BasicHttpBinding is oriented toward the legacy ASMX web services world, which does not have reliability. NetPeerTcpBinding is designed for broadcast scenarios. The MSMQ bindings are for disconnected calls, where no transport session is possible anyway.

Reliability is always enabled on WSDualHttpBinding to keep the callback channel to the client alive even over HTTP.

Reliability is disabled by default but can be enabled on the NetTcpBinding and the various WS bindings. Finally, the NetNamedPipeBinding is considered inherently reliable because it always has exactly one hop from the client to the service.

Ordered Messages

Message reliability also provides ordered delivery assurance, allowing messages to be executed in the order they were sent, not in the order in which they were delivered. In addition, it guarantees that messages are delivered exactly once.

WCF lets you enable reliability but not ordered delivery, in which case messages are delivered in the order in which they were received. The default for all bindings that support reliability is that when reliability is enabled, ordered delivery is enabled as well.

Configuring Reliability

You can configure reliability (and ordered delivery) both programmatically and administratively. When you enable reliability, you must do so on both the client and the service host sides, otherwise the client will not be able communicate with the service. You can only configure reliability for the bindings that support it. Example 1-23 shows the service-side config file that uses a binding configuration section to enable reliability when using the TCP binding.

Example 1-23. Enabling reliability with the TCP binding

<system.serviceModel>
   <services>
      <service name = "MyService">
         <endpoint
            address  = "net.tcp://localhost:8000/MyService"
            binding  = "netTcpBinding"bindingConfiguration = "ReliableTCP"
            contract = "IMyContract"
         />
      </service>
   </services>
   <bindings>
      <netTcpBinding>
         <binding name = "ReliableTCP">
            <reliableSession enabled = "true"/>
         </binding>
      </netTcpBinding>
   </bindings>
</system.serviceModel>

When it comes to programmatic configuration, the TCP and the WS bindings offer slightly different properties for configuring reliability. For example, the NetTcpBinding binding accepts a Boolean construction parameter for enabling reliability:

public class NetTcpBinding : Binding,...
{
   public NetTcpBinding(...,bool reliableSessionEnabled);
   //More members
}

You can only enable reliability at construction time, so when you set reliability programmatically, you need to construct the binding as reliable:

Binding reliableTcpBinding = new NetTcpBinding(...,true);

NetTcpBinding also offers the read-only ReliableSession class, letting you retrieve the reliability status:

public class ReliableSession
{
   public TimeSpan InactivityTimeout
   {get;set;}
   public bool Ordered
   {get;set;}
   //More members
}
public class OptionalReliableSession : ReliableSession
{
   public bool Enabled
   {get;set;}
   //More members
}
public class NetTcpBinding : Binding,...
{
   public OptionalReliableSession ReliableSession
   {get;}
   //More members
}

Requiring Ordered Delivery

In theory, the service code and the contract definition should be independent of the binding used and of its properties. The service should not care about the binding, and nothing in service code pertains to the binding used. The service should be able to work with any aspect of the configured binding. In practice, the service implementation or the contract itself may depend on ordered delivery of the messages. To enable the contract or service developer to constrain the allowed bindings, WCF defines the DeliveryRequirementsAttribute:

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface
                AllowMultiple = true)]
public sealed class DeliveryRequirementsAttribute : Attribute,...
{
   public Type TargetContract
   {get;set;}
   public bool RequireOrderedDelivery
   {get;set;}

   //More members
}

The DeliveryRequirements attribute can be applied at the service level, affecting all endpoints of the service, or only at the endpoints that expose a particular contract. When applied at the service level, it means that requiring ordered delivery is an implementation decision. The attribute can also be used at the contract level, affecting all services that support that contract. When applied at the contract level, it means that requiring ordered delivery is a design decision. Enforcing the constraint is done at the service load time. If an endpoint has a binding that does not support reliability, or supports reliability and has reliability disabled, or has reliability enabled yet ordered delivery is disabled, loading the service will fail with InvalidOperationException.

Tip

The named pipe binding satisfies the ordered delivery constraint.

For example, to demand that all endpoints of the service, regardless of contracts, have ordered delivery enabled, apply the attribute directly on the service class:

[DeliveryRequirements(RequireOrderedDelivery = true)]
class MyService : IMyContract,IMyOtherContract
{...}

By setting the TargetContract property, you can demand that only endpoints of the service that support that contract be constrained to have reliable ordered delivery:

[DeliveryRequirements(TargetContract = typeof(IMyContract),
                      RequireOrderedDelivery = true)]
class MyService : IMyContract,IMyOtherContract
{...}

By applying the DeliveryRequirements attribute on the contract interface, you place the constraint on all services that support it:

[DeliveryRequirements(RequireOrderedDelivery = true)]
[ServiceContract]
interface IMyContract
{...}

class MyService : IMyContract
{...}

class MyOtherService : IMyContract
{...}

The default of the RequireOrderedDelivery is false, so merely applying the attribute has no effect. For example, these statements are equivalent:

[ServiceContract]
interface IMyContract
{...}

[DeliveryRequirements]
[ServiceContract]
interface IMyContract
{...}

[DeliveryRequirements(RequireOrderedDelivery = false)]
[ServiceContract]
interface IMyContract
{...}

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required