Queued Versus Connected Calls

Although it is technically possible to use the same service code both connected and queued (with simple changes such as configuring operations as one-way, or adding another contract for the one-way operations), in reality it is unlikely that you will actually use the same service both ways. The reasons are similar to the arguments made in the context of asynchronous calls, discussed in Chapter 8. Synchronous calls and asynchronous calls addressing the same business scenario often have to use different workflows, and these differences will necessitate changes to the service code to adapt it for each case. The use of queued calls adds yet another barrier for using the same service code (both connected and disconnected): changes to the transactional semantics of the service.

Consider, for example, Figure 9-10, which depicts an online store application that uses connected calls only.

A connected application relies on a single transaction

Figure 9-10. A connected application relies on a single transaction

The Store service uses three well-factored helper services to process the order: Order, Shipment, and Billing. In the connected scenario, the Store service calls the Order service to place the order. Only if the Order service succeeds in processing the order (that is, if the item is available in the inventory) does the Store service call the Shipment service, and only if the Shipment service succeeds does the Store service access the Billing service to bill the customer. The connected case involves exactly one transaction created by the client, and all operations commit or abort as one atomic operation. Now, suppose the Billing service also exposes a queued endpoint for the use of the Store service, as shown in Figure 9-11.

A disconnected application relies on multiple transactions

Figure 9-11. A disconnected application relies on multiple transactions

The queued call to the Billing service will be played to the service in a separate transaction from that of the rest of the store, and it could commit or abort separately from the transaction that groups Order and Shipment. This, in turn, could jeopardize the system's consistency, so you must include some logic in the Billing service to detect the failure of the other service and to initiate some compensating logic in the event that it fails to do its work. As a result, the Billing service will no longer be the same service used in the connected case.

Requiring Queuing

Since not every service can be connected and queued, and since some services may be designed for a particular option and only that option, WCF lets you constrain a service's communication pattern. The DeliveryRequirements attribute presented in Chapter 1 also lets you insist on queued or connected delivery of messages to the service:

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

This attribute can be used to constrain a contract (and all its supporting endpoints) or a particular service type. The default value of the QueuedDeliveryRequirements property is QueuedDeliveryRequirementsMode.Allowed, so these definitions are equivalent:

[ServiceContract]
interface IMyContract
{...}

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

[ServiceContract]
[DeliveryRequirements(QueuedDeliveryRequirements =
                      QueuedDeliveryRequirementsMode.Allowed)]
interface IMyContract
{...}

QueuedDeliveryRequirementsMode.Allowed grants permission for using the contract or the service with either connected or queued calls. QueuedDeliveryRequirementsMode.NotAllowed explicitly disallows the use of the MSMQ binding, so all calls on the endpoint must be connected calls. Use this value when the contract or the service is explicitly designed to be used in a connected fashion only. QueuedDeliveryRequirementsMode.Required is the opposite: it mandates the use of the MSMQ binding on the endpoint, and it should be used when the contract or the service is designed from the ground up to be queued.

Even though the DeliveryRequirements attribute offers the RequireOrderedDelivery property (discussed in Chapter 1), if QueuedDeliveryRequirementsMode.Required is used, then RequireOrderedDelivery must be false, because queued calls inherently are unordered and messages may be played back in any order.

When the DeliveryRequirements attribute is applied on an interface, it affects all services that expose endpoints with that contract:

[ServiceContract]
[DeliveryRequirements(QueuedDeliveryRequirements =
                      QueuedDeliveryRequirementsMode.Required)]
interface IMyQueuedContract
{...}

The client as well can apply the DeliveryRequirements attribute on its copy of the service contract.

When the DeliveryRequirements attribute is applied on a service class, it affects all endpoints of that service:

[DeliveryRequirements(QueuedDeliveryRequirements =
                      QueuedDeliveryRequirementsMode.Required)]
class MyQueuedService : IMyQueuedContract,IMyOtherContract
{...}

When applied on a service class while using the TargetContract property, the attribute affects all endpoints of the service that expose the specified contract:

[DeliveryRequirements(TargetContract = typeof(IMyQueuedContract),
                      QueuedDeliveryRequirements =
                      QueuedDeliveryRequirementsMode.Required)]
class MyService : IMyQueuedContract,IMyOtherContract
{...}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.213.212