Using Reliable Sessions


To handle the problems of lost messages, or messages arriving in the wrong order, the OASIS organization has proposed the WS-ReliableMessaging specification. This specification defines an interoperable protocol for transmitting messages in a reliable manner between a single source and a single destination. Messages can pass through any number of intermediary sites en route to the destination. WCF provides an implementation of this protocol that attempts to ensure that all messages sent from the source will arrive at the destination and without duplication (in other words, exactly once). The protocol implemented by the WCF runtime also attempts to detect missing messages and resend them if possible. At worst, the WCF runtime will throw an exception if a message disappears irrevocably.

WCF optionally supports sequencing, ensuring that messages are processed by the destination in the order that they were sent–the messages might arrive in a different order, but the WCF infrastructure can buffer them to present them to a service in the correct sequence.

More Info 

For detailed information about the WS-ReliableMessaging specification, see the Web Services Reliable Messaging Protocol document on the Microsoft Web site at http://msdn.microsoft.com/library/en-us/dnglobspec/html/WS-ReliableMessaging.pdf.

It is important to understand that reliable messaging as specified by the WS-ReliableMessaging specification does not imply any form of message persistence or message queuing. The protocol requires that both the source application sending the message and the destination application receiving the message are running at the same time. If it is not possible to receive messages, either because the destination application is not running or because of a network failure, the source application will receive an error. In other words, when using reliable messaging, the WCF runtime will guarantee to deliver a message if it can, or it will alert the sender if it cannot–WCF will not silently lose messages.

More Info 

Message queuing implements its own form of reliable messaging through the use of transactions and message durability rather than the WS-ReliableMessaging protocol. You will learn about using message queues as a transport mechanism for WCF messages in Chapter 11, “Implementing OneWay and Asynchronous Operations.”

Implementing Reliable Sessions with WCF

Configuring reliable messaging with a WCF service is a very straightforward task. The WS-ReliableMessaging protocol generates a number of additional messages used by the WCF runtime on the client and service to coordinate their activities, and it is instructive to enable tracing to help you understand how it all works.

Enable reliable sessions in the ShoppingCartService service and client application

  1. Using Visual Studio 2005, open the solution file image from book ShoppingCartService.sln located in the Microsoft Press\WCF Step By Step\Chapter 9\ShoppingCartService folder under your \My Documents folder.

    This solution contains a copy of the completed ShoppingCartService, and ShoppingCartServiceHost and ShoppingCartClient projects from Chapter 8, “Supporting Transactions.” Remember that the ShoppingCartService service exposes a TCP endpoint and requires the client application to create a transaction to maintain the integrity of the database.

    Note 

    This set of exercises uses the NetTcpBinding binding and transport level security. This enables you to easily examine the messages and headers generated by the reliable messaging protocol. Reliable messaging works with the WSHttpBinding over an HTTP endpoint with message level security in exactly the same way. However, in this configuration the messages are intermingled with other messages negotiating the various security tokens, and the messages also contain encrypted data and additional headers making it more difficult to pick out the elements associated with reliable messaging.

  2. In Solution Explorer, edit the image from book App.config file for the ShoppingCartHost project by using the WCF Service Configuration Editor.

  3. In the WCF Service Configuration Editor, in the Bindings folder, select the ShoppingCartServiceNetTcpBindingConfig binding configuration. In the right pane, scroll down to display the ReliableSession Properties section and then set the Enabled property to True. Verify that the Ordered property is set to True, and note that the InactivityTimeout property is set to 10 minutes by default.

    The WCF runtime uses the Ordered property to determine whether to pass messages to the service in the same order that the client sent them; this is an optional but useful feature of reliable messaging. The WCF runtime will wait for the time period specified by the InactivityTimeout property between messages before deciding that something has gone wrong and messages have gone missing. If this timeout expires, the WCF runtime sends a “sequence terminated” SOAP fault message to the client application (which it might not receive if the client application is no longer running or communications have failed) and then terminates the session, rolling back any changes that have occurred if the service uses transactions.

    Note 

    If you are using the NetTcpBinding or NetNamedPipeBinding bindings you must also verify that the TransferMode property in the General section of the binding configuration page is set to Buffered.

    The TransferMode property specifies that the WCF runtime buffers complete messages in memory before passing them to the service or sending out responses. The TCP and named pipe transports, also support streaming, which enables you to send large messages as a series of small chunks. In this mode, the receiver does not have to wait for the sender to finish transmitting the message before it can start processing it. Using streaming removes the need for holding large messages in memory and can improve scalability. However, the implementation of reliable sessions in WCF requires that an entire message has been received before it can be processed, so buffering is mandatory.

    If you are using the WSHttpBinding binding, messages are automatically buffered (the HTTP protocol does not support streaming).

    Incidentally, transactions and message-level security also require WCF to buffer messages before transmitting them.

  4. You will examine the messages generated by the WS-ReliableMessaging protocol, so the next step is to configure tracing.

    In the left pane, click the Diagnostics folder. In the right pane, click the EnableMessageLogging link.

  5. In the left pane, expand the Diagnostics folder and then click the Message Logging node. In the right pane, set the LogEntireMessage property to True and set the LogMalformedMessages property to False.

  6. In the left pane, expand the Listeners folder and then click the ServiceModelMessageLogggingListener node. In the right pane, change the path in the InitData property to refer to the file app_messages.svclog in the Microsoft Press\WCF Step By Step\Chapter 9 folder under your My Documents folder.

  7. Save the configuration file and then exit the WCF Service Configuration Editor.

  8. The binding configuration for the client endpoint must match the properties used by the service endpoint.

    In Solution Explorer, edit the image from book App.config file for the ShoppingCartClient project. Display the properties for the ShoppingCartClientNetTcpBindingConfig binding configuration, and set the Enabled property in the ReliableSession Properties section to True. Verify that the Ordered property is set to True, and the InactivityTimeout property is set to 10 minutes.

    Reliable messaging in the client application can cause a timeout and throw an exception if it doesn’t receive any messages within the period specified by the InactivityTimeout property. However, a client application normally only receives messages in response to a request (in Chapter 14, “Using a Callback Contract to Publish and Subscribe to Events,” you will see that it is also possible for a client application to receive messages at other times). It is possible for a client application to become quiescent on the network, but remain active even if it is not sending messages to a service (it might be busy displaying data, or gathering user input, for example). Similarly, it was mentioned earlier that a WCF service can timeout if it doesn’t receive any messages within the period specified by its own InactivityTimeout property. To prevent this happening unnecessarily, the WCF runtime on the client computer will periodically send a “keep alive” message to the service if the client application has not sent any messages recently. The point at which this happens is approximately half the value of the InactivityTimeout period specified in the client application configuration file. This “keep alive” message actually serves a dual purpose: it lets the service know the client application is still running, and it probes to make sure that the service is still accessible. The WCF runtime on the client computer expects the WCF runtime on the server computer to reply with an acknowledgement message, and if this acknowledgement is not received within the period specified by the InactivityTimeout property, the WCF runtime on the client application assumes that the service has died and generates a “sequence terminated” SOAP fault message that the client application should handle.

  9. Save the configuration file and then exit the WCF Service Configuration Editor.

Examine the trace messages generated by the client application

  1. Start the solution without debugging. In the ShoppingCartClient console window displaying the message “Press ENTER when the service has started,” press Enter.

    The client application executes as before, displaying the shopping cart containing two water bottles and a mountain seat assembly, followed by the “Goods purchased” method. Press Enter to close the client application console window. In the host application console window, press Enter to stop the service and close the application.

  2. Start the Service Trace Viewer (in the Windows Start menu, point to All Programs, point to Microsoft Windows SDK, point to Tools, and then click Service Trace Viewer).

  3. In the Service Trace Viewer, open the app_messages.svclog file in the WCF Microsoft Press\Step By Step\Chapter 9 folder under your My Documents folder.

  4. In the left pane, click the Message tab. Click the first message. In the lower right pane, click the Message tab. Examine the contents of this message; it should look like this. (The format of the message has been adjusted to fit on the page. Your MessageID and Identifier properties will be different from those shown here):

     <s:Envelope …>   <s:Header>     <a:Action s:mustUnderstand="1">       http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence     </a:Action>     <a:MessageID>       urn:uuid:     </a:MessageID>     <a:To s:mustUnderstand="1">       net.tcp://localhost:9080/ShoppingCartService     </a:To>   </s:Header>   <s:Body>     <CreateSequence xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">       <AcksTo>         <a:Address>           http://www.w3.org/2005/08/addressing/anonymous         </a:Address>       </AcksTo>       <Offer>         <Identifier>           urn:uuid:         </Identifier>       </Offer>     </CreateSequence>   </s:Body> </s:Envelope>

    The WS-ReliableMessaging protocol organizes messages in a conversation between a client application and a service by associating them with a unique identifier known as a sequence number. The first message in the protocol is this CreateSequence message, sent by the WCF runtime on the client computer. This message initiates the reliable session. All messages in the same reliable session must share the same set of identifiers, and the body of this message contains a unique identifier generated by the WCF runtime (highlighted in bold) that the service should use when responding to the client application.

  5. In the left pane, click the second message, and then examine the contents of this message in the lower right pane. It should look like this:

     <s:Envelope …>   <s:Header>     <a:Action s:mustUnderstand="1">        http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequenceResponse     </a:Action>     <a:RelatesTo>       urn:uuid:     </a:RelatesTo>     <a:To s:mustUnderstand="1">       http://www.w3.org/2005/08/addressing/anonymous     </a:To>   </s:Header>   <s:Body>     <CreateSequenceResponse xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">       <Identifier>         urn:uuid:       </Identifier>       <Accept>         <AcksTo>           <a:Address>             net.tcp://localhost:9080/ShoppingCartService           </a:Address>         </AcksTo>       </Accept>     </CreateSequenceResponse>   </s:Body> </s:Envelope>

    This is the CreateSequenceResponse message, sent back to the client by the WCF runtime on the service computer. Note that the body of this message also contains an identifier (shown in bold). The WCF runtime on the client must provide this identifier when sending further messages to the service.

  6. Examine the contents of third message. It should look like this (some elements have been removed for clarity):

     <s:Envelope …>   <s:Header>     <r:AckRequested>       <r:Identifier>         urn:uuid:       </r:Identifier>     </r:AckRequested>        <r:Sequence s:mustUnderstand="1">          <r:Identifier>         urn:uuid:       </r:Identifier>       <r:MessageNumber>         1       </r:MessageNumber>     </r:Sequence>         </s:Header>   <s:Body>     <AddItemToCart xmlns="http://adventure-works.com/2007/03/01">       <productNumber>         WB-H098       </productNumber>     </AddItemToCart>   </s:Body> </s:Envelope>

    This is the first AddItemToCart message sent by the client application. The key thing to notice in this message is the <Sequence> block, shown in bold. The identifier in this block is the same as the identifier returned in the CreateSequenceResponse message by the service. All messages transmitted from the client application to the service participating in the reliable session must include this information in the SOAP header. They should also include a message number–in this case message “1”–enabling the WCF runtime on the server computer to ensure that messages are passed to the service in the correct order. You should also notice that the SOAP header includes an <AckRequested> block. When the WCF runtime on the server computer receives this message it must send an acknowledgement message back to the client computer so that the client knows it has been received.

  7. Examine the contents of the fourth message. It should look like this:

     <s:Envelope …>   <s:Header>     <r:SequenceAcknowledgement>       <r:Identifier>         urn:uuid:       </r:Identifier>       <r:AcknowledgementRange Lower="1" Upper="1">       </r:AcknowledgementRange>       <netrm:BufferRemaining xmlns:netrm="http://schemas.microsoft.com/ws/2006/05/rm">         8       </netrm:BufferRemaining>     </r:SequenceAcknowledgement>     <a:Action s:mustUnderstand="1">       http://schemas.xmlsoap.org/ws/2005/02/rm/SequenceAcknowledgement     </a:Action>     …   </s:Header>   <s:Body></s:Body> </s:Envelope>

    This is the acknowledgement message from the WCF runtime on the server computer, back to the WCF runtime on the client computer. The service has verified that it has received the AddItemToCartMessage.

  8. Look at the fifth message:

     <s:Envelope …">   <s:Header>     <r:AckRequested>       <r:Identifier>         urn:uuid:       </r:Identifier>     </r:AckRequested>     <r:Sequence s:mustUnderstand="1">       <r:Identifier>         urn:uuid:       </r:Identifier>       <r:MessageNumber>         1       </r:MessageNumber>     </r:Sequence>     <a:Action s:mustUnderstand="1">       http://adventure-works.com/2007/03/01/ShoppingCartService/AddItemToCartResponse     </a:Action>          </s:Header>   <s:Body>     <AddItemToCartResponse xmlns="http://adventure-works.com/2007/03/01">       <AddItemToCartResult>         true       </AddItemToCartResult>     </AddItemToCartResponse>   </s:Body> </s:Envelope>

    This is the AddItemToCartResponse message, indicating that the service successfully added the specified item to the shopping cart. Again, notice how this message requires the client to acknowledge its receipt, that the identifier used in the <Sequence> block is the identifier specified by the client at the start of the session, and that this is also message “1” (in the opposite direction from the client message). If you examine the sixth message, you will see that it is the acknowledgement for this AddItemToCartReponse message from the client sent back to the service.

  9. Examine messages seven through fourteen. You can see that things settle down at this point, and the conversation consists of request messages sent by the client application and the response messages sent back from the service. These messages all contain a <Sequence> block with the appropriate identifier. Each message also has a message number, which is incremented for each new message in each direction (the next message in the sequence sent from the client application to the service is message “2,” and the response message sent by the service back to the client is also message “2”).

    Note 

    If it helps, think of the request/response messages as a series of two synchronized one-way conversations. Each message traveling in one direction forms part of a sequence, and the messages in this sequence are numbered starting at 1. The messages traveling in the opposite direction form part of a different sequence and are also numbered starting at 1. The message numbers do not tie messages together; response message 1 might or might not be the response for request message 1.

    As an optimization mechanism, after the initial request/response messages the message acknowledgements are incorporated into the next request or response messages sent by the client application or service–the header in a message being sent contains the acknowledgement for the previous message received.

    Note 

    The <SequenceAcknowledgement> block in messages seven through fourteen also includes a BufferRemaining element. As already mentioned, to handle messages arriving out of order, the WCF runtime buffers them before handing them off to the application. If a message with a high message number is received when the runtime was expecting a lower message number, the higher numbered message will be held in a buffer until the lower numbered message has been received and passed to the application. The WCF runtime provides a finite number of buffers for a session. If a client application sends a large volume of messages to a service and many arrive out of order, the WCF runtime on the server computer may run out of buffers and start to drop messages (they are resent when more space is available). Therefore, when acknowledging a message, the WCF runtime also provides the number of free buffers it currently has in the BufferRemaining element. The WCF runtime on the client computer can examine this value and suspend sending messages if this number minus the number of messages the client has sent but have not yet been acknowledged (they are in transit) drops below a certain threshold (currently 2). As the WCF runtime on the server receives the missing messages it can pass them to the service and hopefully free up some of the buffers. Subsequent acknowledgement messages from the service should indicate that more buffer space is available, and the WCF runtime on the client computer can resume sending messages. This is a WCF-specific feature-if an application built using another technology does not understand this element, it will be ignored.

  10. Examine message fifteen. It should look like this:

     <s:Envelope …>   <s:Header>     <r:SequenceAcknowledgement>       <r:Identifier>         urn:uuid:       </r:Identifier>       <r:AcknowledgementRange Lower="1" Upper="5">       </r:AcknowledgementRange>       <netrm:BufferRemaining xmlns:netrm="http://schemas.microsoft.com/ws/2006/05/rm">         8       </netrm:BufferRemaining>     </r:SequenceAcknowledgement>     <r:Sequence s:mustUnderstand="1">       <r:Identifier>         urn:uuid:       </r:Identifier>       <r:MessageNumber>         6       </r:MessageNumber>       <r:LastMessage>       </r:LastMessage>     </r:Sequence>     <a:Action s:mustUnderstand="1">       http://schemas.xmlsoap.org/ws/2005/02/rm/LastMessage     </a:Action>     <a:To s:mustUnderstand="1">       net.tcp://localhost:9080/ShoppingCartService     </a:To>   </s:Header>   <s:Body>   </s:Body> </s:Envelope>

    This is the LastMessage message. It is sent by the WCF runtime on the client computer to indicate that this is the final message in the sequence. This message is sent when the client application starts to close the session. The WCF runtime on the server computer acknowledges this message (see message sixteen) and then sends its own LastMessage message to indicate that it has also finished (message seventeen). The WCF runtime on the client computer sends an acknowledgement (message eighteen).

  1. Examine message nineteen:

     <s:Envelope …>   <s:Header>     <a:Action s:mustUnderstand="1">       http://schemas.xmlsoap.org/ws/2005/02/rm/TerminateSequence     </a:Action>     …   </s:Header>   <s:Body>      <TerminateSequence xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">       <Identifier>         urn:uuid:       </Identifier>      </TerminateSequence>    </s:Body> </s:Envelope>

    This is the TerminateSequence message. The WCF runtime on the server computer sends this message to indicate that it is not going to send any more messages using the sequence specified by the identifier and that the WCF runtime on the client computer can release any resources associated with this session. The WCF runtime on the client computer also sends a TerminateSequence message to the server (message twenty), identifying the sequence used by the client to send messages to the server. At the end of this exchange, the session terminates.

  2. Close the Microsoft Service Trace Viewer and delete the trace file.

These exercises should make two things apparent to you:

  • It is very easy to implement reliable messaging with WCF. You just set a few properties of the binding configuration. You don’t need to write any additional code; it is all transparent to your client applications and services.

  • Reliable sessions can generate a significant amount of additional network traffic, both in terms of the extra protocol messages and the increased size of each message. The more messages a client application sends in a session, the smaller this overhead becomes proportionally. However, if you use short sessions, comprising a single request and response for example, each request sent by a client application establishes a new reliable session that is thrown away after a response has been received. This is expensive, and in this situation you should consider very carefully whether you really need reliable messaging or whether you should rework the client application to make more efficient use of reliable sessions.

Reliable messaging works well with the PerCall service instance context mode. Although the WCF runtime creates a new service instance for each request, it creates the sequence for the reliable session when the client application makes the first call to the service in the session, and only terminates the sequence when the session ends. Ideally, you should set the SessionMode property of the service contract to SessionMode.Required to ensure that the client application actually establishes a session.

You should also be aware that not all binding configurations support the WS-ReliableMessaging protocol. The ones that do are netTcpBinding, wsDualHttpBinding (this binding always uses reliable messaging, you cannot disable it), wsFederationHttpBinding, and wsHttpBinding. The MSMQ bindings, msmqIntegrationBinding and netMsmqBinding, implement their own version of reliable messaging based on message persistence and queuing technologies rather than WS-ReliableMessaging. The common bindings that do not support reliable messaging include basicHttpBinding, netNamedPipeBinding, and netPeerTcpBinding.

Note 

You can also create custom bindings that support reliable sessions. You will see how to define a custom binding later in this chapter, and also in Chapter 10, “Programmatically Controlling the Configuration and Communications.”




Microsoft Windows Communication Foundation Step by Step
Microsoft Windows Communication Foundation Step by Step (Step By Step Developer Series)
ISBN: 0735623368
EAN: 2147483647
Year: 2007
Pages: 105
Authors: John Sharp

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net