Reliability

WCF and other service-oriented technologies make a distinction between transport reliability and message reliability. Transport reliability (such as that offered by TCP/IP) offers point-to-point guaranteed delivery at the network packet level and also guarantees in-order delivery of the packets. Transport reliability is not resilient to dropped network connections or 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 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 and supports retries in case of transport failures, such as dropping a wireless connection. It automatically deals with congestion, message buffering, and flow control, and can adjust the flow of messages accordingly. Message reliability also deals with connection management, verifying connections and cleaning them up when they are no longer needed.

Note

Message reliability does not guarantee message delivery. It provides only a guarantee that if the message does not reach its destination, the sender will know about it.

Bindings, Reliability, and Ordered Messages

In WCF, you control and configure reliability in the binding. A particular binding can support or not support reliable messaging and, if it’s supported, you can enable or disable it. Whether a binding supports reliability is driven by the target scenario for that particular binding. Table 1-2 summarizes the relationship between binding, reliability, and ordered delivery for the six commonly used bindings and lists the respective default values.

Table 1-2. Reliability and ordered delivery

Binding name

Supports reliability

Default reliability

Supports ordered delivery

Default ordered delivery

BasicHttpBinding

No

N/A

No

N/A

NetTcpBinding

Yes

Off

Yes

On

NetNamedPipeBinding

No

N/A (On)

Yes

N/A (On)

WSHttpBinding

Yes

Off

Yes

On

NetMsmqBinding

No

N/A

No

N/A

The BasicHttpBinding and the NetMsmqBinding do not support reliability. The BasicHttpBinding is oriented toward the legacy ASMX web services world, which does not support reliability, while the NetMsmqBinding is for disconnected calls and has its own notion of reliability (discussed in Chapter 9).

Reliability is disabled by default, but you can enable it in the NetTcpBinding and the WSHttpBinding. Finally, the NetNamedPipeBinding is considered inherently reliable because it always has exactly one hop from the client to the service.

Message reliability also provides ordered delivery assurance, allowing execution of messages in the order in which they were sent, not the order in which they were delivered. In addition, it guarantees that each message is delivered exactly once.

WCF lets you enable reliability but not ordered delivery, in which case messages are executed 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. Ordered delivery requires reliability. Thus, if ordered delivery is turned on but reliability is turned off, the calls will not be delivered in order.

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, or the client will not be able to communicate with the service. You can only configure reliability for the bindings that support it. Example 1-24 shows a service-side config file that uses a binding configuration section to enable reliability when using the TCP binding.

Example 1-24. 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 WS bindings both offer a construction parameter and a property 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 also enable reliability post-construction by accessing the ReliableSession property:

public class ReliableSession
{
   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 its properties. The service should not care about the binding, and nothing in the service code pertains to the binding used. The service should be able to work with any aspect of the configured binding. In practice, however, 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
}

You can apply the DeliveryRequirements attribute at the service level, affecting all endpoints of the service, or only at those endpoints that expose a particular contract. When applied at the service level, requiring ordered delivery is an implementation decision. 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 the specified contract be constrained to have reliable ordered delivery:

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

You can also use the attribute at the contract level, affecting all services that support that contract. When applied at the contract level, requiring ordered delivery is a design decision. Enforcing the constraint is done at service load time. If an endpoint has a binding that does not support reliability, supports reliability but has it disabled, or has reliability enabled but ordered delivery disabled, loading the service will fail with an InvalidOperationException.

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

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

class MyService : IMyContract
{...}

class MyOtherService : IMyContract
{...}

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

[ServiceContract]
interface IMyContract
{...}

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

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

Note

The IPC binding satisfies the ordered delivery constraint.

Get Programming WCF Services, 3rd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.