You are on page 1of 20

DuplexHttpBinding: Callback Contracts in the Cloud with a Custom WCF Channel

Contents
Introduction Duplex over HTTP.................................................................................................................. 2 Callbacks in WCF ....................................................................................................................................... 2 Fundamental Design Goals of DuplexHttpBinding....................................................................................... 3 WCF Channel Model Basics: Channel Shape and Callbacks over HTTP ........................................................ 4 Channels Have Shape .............................................................................................................................. 4 4 Types of Application Messages .............................................................................................................. 5 Why is Polling Necessary?......................................................................................................................... 6 Smart Polling ............................................................................................................................................... 6 PollingInterval, PollingReplyInterval ......................................................................................................... 7 Starting, Stopping and Adjusting Polling Based on the Applications Needs ............................................ 7 Message Batching ..................................................................................................................................... 9 Server and Client Queue Throttles.......................................................................................................... 10 A Word about WCF Channels and Sessions ................................................................................................ 11 DuplexHttpBinding Quick Reference .......................................................................................................... 11 Client Binding Properties ........................................................................................................................ 11 Server Binding Properties ....................................................................................................................... 12 DuplexHttpPollingBehavior ..................................................................................................................... 13 Sample Server Configuration File............................................................................................................ 13 Sample Client Configuration File............................................................................................................. 14 The Sample Application .............................................................................................................................. 15 Quick Start............................................................................................................................................... 15 Alert Service ............................................................................................................................................ 16 WindowsHost .......................................................................................................................................... 17 WindowsClient ........................................................................................................................................ 18 Silverlight 2 and Duplex Over HTTP. ........................................................................................................... 19 Additional Resources .................................................................................................................................. 20 1

Introduction Duplex over HTTP.


Modern applications achieve their full potential by combining rich, highly intuitive user experiences with flexible networking capabilities. They are no longer restricted to data and services that are available only on the local machine or local network, but instead rely on loosely coupled external services that may be located anywhere on the internet. In addition to the ability of an application to make requests of external services, there often exists the need for these services to send unsolicited messages directly to the application. This ability for a client application and a service to independently send each other messages is known as the duplex message exchange pattern. Unfortunately duplex communication is hard to achieve using the internets ubiquitous HTTP networking protocol because HTTP enables a client application to easily send a request to a service, but the service does not have the ability to freely send requests to the client. This paper and sample code introduce a custom extension to .NETs messaging infrastructure to address the complexity of enabling duplex over HTTP.

Callbacks in WCF
Windows Communication Foundation (WCF) is the messaging subsystem in the .NET platform that enables a wide range of message-based communication scenarios. WCF supports duplex communication by enabling a higher level programming model that allows a service to invoke methods on the client directly. This is implemented by using metadata to identify an interface known as the callback contract. The client application hosts an object that implements the callback contract and after the client calls at least one operation on the service, the service can capture a pointer to the client and then invoke operations on the callback contract whenever it wants to without having to wait for the client to initiate the communication. The clients responsibility is to simply keep the communication channel open. In keeping with WCFs terminology, this paper will use the term callback to refer to this ability for a service to send a message directly to a client. A typical usage pattern for callbacks is to implement an event notification mechanism. For example, a weather monitoring service could notify a subscribed client application that the temperature has dropped below freezing without the client having to continually ask the service what the current temperature is. Callbacks are a very powerful capability, but out of the box WCF only enables this duplex messaging pattern when the client can be directly contacted via a known network address, such as when the client application is running inside a corporate network. Using the bindings that ship with WCF, a client out in the cloud that is connected to the internet but sitting behind a firewall cannot receive WCF callback messages from a service unless a hole is opened in the firewall to explicitly allow it. Therefore, applications built to take advantage of WCFs duplex communication capabilities are limited to specific network scenarios. DuplexHttpBinding is a sample implementation of a custom WCF binding and protocol channel that overcomes this limitation. It enables a .NET application to leverage the WCF callback programming 2

model when connected to a WCF service over the internet - using the familiar HTTP protocol on the default port 80. There are many application scenarios where DuplexHttpBinding will be useful. Outlook, although not an application that uses WCF for communication, is a familiar example. Messages are pushed directly to Outlook from the Exchange server when it is on the corporate network and this messaging pattern continues to work when outside the corporate network because Outlook automatically switches to a different connection protocol. Like Outlook, a .NET application using WCF could automatically switch from the NetTcpBinding when on the corporate network to the DuplexHttpBinding when out in the cloud. Application code does not have to be written to support the different network scenarios. WPF XBAP applications are another scenario where the DuplexHttpBinding will be useful. An XBAP (XAML Browser Applications) is a type of WPF client application that is characterized by its web-like deployment mechanism. XBAPs are rich WPF client applications that are launched and hosted by a browser. Due to restrictions imposed by the partial trust default security context that XBAPs run in, they can only communicate with WCF services over the HTTP transport and they are not typically directly addressable by a WCF service. The DuplexHttpBinding will allow XBAPs to leverage the full capabilities of WCF callback contracts in partial trust. This paper will walk through the architecture, design and implementation details of the DuplexHttpBinding custom WCF binding and its underlying custom protocol channels that provide the implementation. It is assumed the reader has both an understanding of how WCF enables the duplex programming model via its support of callback contracts and an entry level understanding of the WCF channel model. Please refer to the resources at the end of this paper to learn more about these topics if necessary.

Fundamental Design Goals of DuplexHttpBinding


The following are the design goals for this custom WCF binding: 1. DuplexHttpBinding must provide a WCF channel stack that enables the duplex message exchange pattern (I.E. supports WCFs Callback contract programming model). 2. DuplexHttpBinding must provide a WCF channel stack that communicates over the internet (HTTP on port 80), without requiring any additional network or firewall configuration. 3. DuplexHttpBinding must work in a partial trust .NET application, such as a WPF XBAP application. 4. DuplexHttpBinding must be a configuration alternative to the TCP based NetTcpBinding, enabling an application to use the most appropriate communication protocol for the current network scenario (I.E. inside the firewall or outside the firewall).

WCF Channel Model Basics: Channel Shape and Callbacks over HTTP
In order to understand how the DuplexHttpBinding works, it is necessary to review the role that channel shape plays in exposing the messaging capabilities of a specific transport and how this factors into the design of this custom binding.

Channels Have Shape


The WCF platform has been architected in 2 fundamental layers known as the service model and the channel model. The service model enables the friendly programming environment for developing services and service clients; it is the service model that exposes WCFs callback capabilities to the application developer. Below the object oriented programming environment provided by the service model is the channel model - this is where the details of the messaging protocols are implemented and messages are read from and written to the wire. A fundamental construct in the channel model is the channel stack, which is a series of .NET classes called channels. Channels are arranged in a stack such that only the top channel in the stack is exposed to the application. Messages are processed in the channel model by being passed through the channel stack, where at the bottom they are read from and written to the network. In order for the service model to support the duplex message exchange pattern as implemented via the callback programming model described above, both the service and the client must have the ability to freely send each other messages. This ability to freely send and receive messages is exposed to the service model by the channel stack it is using to process the messages. So therefore the channel stacks on both the client and the server must support duplex communication. A WCF channel stack that supports duplex implements the IDuplexChannel interface and is thus said to have the duplex channel shape. The IDuplexChannel interface has a Send() method and a Receive() method. The service model pushes all outbound messages through the channel stack via the Send() method and it reads all inbound messages from the channel via the Receive() method. Now, of course the channel stacks ultimate responsibility is to read and write messages to the underlying network, so the network protocol must be capable of allowing both the client and the service to send and receive. Connection oriented network protocols such as TCP and named pipes support this type of network I/O and this is why channel stacks created by WCFs NetTcpBinding and NetNamedPipeBinding classes can support callbacks. In contrast to the connection oriented nature of TCP and named pipes, the HTTP protocol does not support the ability for the server to freely send messages to the client. HTTP is a request/reply protocol which means a client can send a request to the server and receive a reply in response, but the service cannot send a request to the client. The service can only listen for incoming requests and respond to those requests with a reply message. The request/reply message exchange pattern is implemented in WCF channels with the IRequestChannel interface on the client side and the IReplyChannel interface on the server side. Unlike IDuplexChannel, the IRequestChannel interface does not have a Send() or a Receive() method, instead it has a Request() method that takes the message to be sent as a parameter and returns a message as the reply. Similarly, the service sides IReplyChannel interface also does not have a Send() or Receive() method, but instead it has a ReceiveRequest() method which returns a 4

message and provides a mechanism to allow the service to send back the reply to that message. A commonly used WCF binding that supports the HTTP protocol is the BasicHttpBinding, but unfortunately, because its channel stack is a request/reply shape and not a duplex shape, it does not support callbacks. The goal of the custom DuplexHttpBinding class is to support callbacks over HTTP. It therefore needs to implement a channel stack that looks to the service model like it is a duplex channel even though the HTTP transport channel that it is using to do network I/O does not support duplex communication. On the client side, the channel at the top of the channel stack created by the DuplexHttpBinding is the custom HttpPollingRequestChannel. HttpPollingRequestChannel is an IDuplexChannel that, as the name implies, establishes communication with the WCF service by sending internal polling messages through the HTTP transport channel below it in the stack. Because this HTTP transport channel is not a duplex channel but is instead an IRequestChannel, it is said that the HttpPollingRequestChannel shifts its shape from IDuplexChannel to IRequestChannel. On the service side, the top channel in DuplexHttpBindings channel stack is the custom HttpPollingReplyChannel. HttpPollingReplyChannel is also an IDuplexChannel that shifts shape to an IReplyChannel. As an IReplyChannel, it listens for the internal polling messages sent by the client and uses the reply to those messages as its opportunity to deliver all outbound messages from the server to the client. To put it another way: these internal HTTP requests and their associated replies sent from the client to the server provide the vehicle for transporting the applications SOAP messages and enable the channel to fool the service model into thinking that the server can send messages directly to the client whenever it wants to.

4 Types of Application Messages


A key to understanding how this channel works to enable callbacks is to remember that a WCF channel just works with messages. The service model layer provides all of the magic that transforms a method call into a message (known as serialization) on the sender and then transforms a message into a method call on the receiver (known as deserialization). In the case of an IDuplexChannel, the channel model is responsible for implementing the Send() and Receive() methods in a way that ensures that the messages make their way back and forth between the client and the service. There are essentially 4 types of application messages being sent through the WCF channel in an application that supports the duplex message exchange pattern: 1. Messages that result from the client invoking a method on the service contract. These are messages sent from the client to the service. 2. Messages that result from the service operations return value. These are messages sent from the service to the client. 3. Messages that result from the service invoking a method on the clients callback contract. These are messages sent from the service to the client.

4. Messages that result from the client callback operations return value. These are messages sent from the client to the service. The client application (usually the WCF service model layer) calls Send() on the channel to send messages 1 and 3 to the service, and the client application calls Receive() on the channel when it is ready to accept messages 2 and 4 from the service. Conversely, the service application calls Send() on the service side channel to send messages 2 and 4 to the client and it calls Receive() on the service side channel when it is ready to accept messages 1 and 3 from the client. As channel model developers, it is safe from this point on to pretty much forget about what about the application is doing and simply get down to the business of implementing the Send() and Receive() methods. As you explore the sample code, resist the urge to care about what the service model and/or the application are doing with the messages and it will be easier to understand.

Why is Polling Necessary?


When the service calls Send() on the channel stack to send a message to the client, the channel cant actually send the message directly to the client at that time - because the client and server are using HTTP to communicate. The only way for the service channel to get messages to the client channel is to send them out as the reply to an inbound request. So, the Send() implementation puts the outbound message in a queue and returns. As far as the application knows, the message is on its way. The client side channel has the responsibility of sending polling requests to the service on a regular interval to pick up any messages that are waiting in that queue. In addition to the internal polling messages being sent from the client channel to the service channel, the client application will also be sending real application messages to invoke operations on the service contract. The service side channel has to hand these real application messages up to the service model in response to the service model calling Receive() on the channel stack. But regardless of whether the message received from the client was a real application message or an internal polling message, the service channels reply to an inbound message is used as the vehicle to send any outbound messages waiting in the queue. An internal channel strategy that relies on polling can of course lead to an inefficient use of network bandwidth and server resources. If implemented incorrectly it can also result in high latency, making the application feel sluggish. Many techniques are available to make the polling as efficient as possible. The next section will discuss in more detail the strategy for how the polling scheme is implemented and how the application developer can affect the polling behavior.

Smart Polling
Polling has the potential to add a lot of unnecessary network activity. Most of the complexity of this custom channels implementation is the result of logic attempting to make the polling as efficient as possible.

PollingInterval, PollingReplyInterval
Increasing the frequency that polling messages are sent to the server will make the application more responsive because there will be less latency between when the service sends messages and when the client actually receives them. But this will also lead to wasted network round trips when there are no messages on the server waiting to go to the client. The polling frequency is controlled by a configuration property called PollingInterval. A popular technique known as long polling can reduce unnecessary round trips. With long polling, the service side channel receives the polling request and if no messages are waiting to go back to the client, it hold the connection open for a specified amount of time, waiting until it has a message to send back as the reply. This greatly reduces the network traffic and decreases message latency, but can cause a strain on precious server connection resources. The interval that the server will hold a connection open while waiting for a reply is controlled by a configuration property called PollingReplyInterval. The trick is to balance the PollingInterval and the PollingReplyInterval as appropriate for the application, the network resources and the server resources. The PollingInterval however is only a suggestion. The client and service channels communicate with each other by sending custom headers in the SOAP message. If the client channel learns that there are more messages waiting to go at the server, it will not wait on the PollingInterval, but will immediately turn around and send another polling request. This continues until the service channel has no more messages waiting in its queue. In a similar manner, the PollingReplyInterval is only a suggestion. The PollingReplyInterval is configured on the client, providing the ability for different clients communicating with the same service to be configured independently. But the service has the final say in how long it will hold open expensive network connections. The service channel has a MaxPollingReplyInterval configuration property to support this.

Starting, Stopping and Adjusting Polling Based on the Applications Needs


In addition to adjusting the polling interval and the polling reply interval with configuration properties, the polling behavior can also be affected by the applications messaging requirements. When a client application invokes an operation on a service that returns a value, the client application expects and waits for a return message from the service. The client channel can peak at that outbound message and learn that the application is expecting a return message. Until that return message has arrived, the client channel will not wait on the PollingInterval to send the polling messages required to pick up that reply. Instead it will behave as it does when it knows the server has messages waiting to send and continue sending polling requests as quickly as it can until all outstanding expected replies are back from the service (or until the message times out). This enables the polling interval to be set longer to more lazily poll for the unexpected callback messages without sacrificing response time for replies to service operations. It addition to this simple polling interval adjustment, it often makes sense to consider other aspects of the applications needs when trying to optimize the channels polling behavior. A common application pattern uses WCF duplex communication for implementing an event mechanism where the client will 7

invoke a service operation to subscribe to an event and invoke a different service operation to unsubscribe from that event. While subscribed, the service could be sending event notifications directly to the client. In this pattern, the client channel only has to be continuously sending polling messages if the application is currently subscribed. If it is not subscribed, the service will not be sending any unsolicited messages so there is no need to poll for them. For example, an application that helps a wine vineyard owner manage her operation might leverage a weather service to retrieve weather conditions. The weather service provides a Freeze Alert that the client can optionally subscribe to. Perhaps the application is configured to subscribe to the freeze alert in the winter months but not in the summer. When the application is not subscribed, there is no need for the channel to poll. The weather service has 2 operations that enable subscribing to freeze alerts, the FreezeAlertSubscribe() and FreezeAlertUnsubscribe() methods. These are the triggers that need to start and stop polling. The custom DuplexHttpPollingBehavior attribute can be applied to the operations on the service contract to enable this behavior thus allowing a service operation to start polling, stop polling, or adjust the polling interval. Consider the following contract for this sample weather service:
[ServiceContract(CallbackContract = typeof(IWeatherServiceCallback))] public interface IWeatherService { [OperationContract] [DuplexHttpPollingBehavior(PollingAction.Start, PollingInterval = "00:00:05")] void FreezeAlertSubscribe(); [OperationContract] [DuplexHttpPollingBehavior(PollingAction.CorrelatedStop, StartAction = "FreezeAlertSubscribe")] void FreezeAlertUnsubscribe(); }

When DuplexHttpBindings client channel (HttpPollingRequestChannel) is processing outbound messages, it will know that it needs to start polling when it sees that the client application is invoking the FreezeAlertSubscribe() operation. And in this case, if the configured polling interval is currently greater than 5 seconds, then it needs to be sped up to a 5 second interval. Adjusting the polling interval at the operation level enables an application to speed up polling as it subscribes to more time sensitive events. If the HttpPollingRequestChannel subsequently sees that the application is invoking the FreezeAlertUnsubscribe() operation, it will suspend polling. The polling start and stop behaviors can be applied to an unlimited number of service operations. The CorrelatedStop action in the above sample takes a StartAction parameter, which is a delimited list of start actions. This links the stop request to a start request. Polling will only be stopped if it is currently active and was initiated by one of these start actions and there are no other outstanding start actions. In addition to the CorrelatedStop polling behavior, an operation can be configured with the hard Stop PollinigAction, which will cause polling to be suspended, regardless of how it was started. 8

If at least one service contract operation is configured to start polling, then by default, polling will not start when the channel is opened. If however there are no operations configured with the DuplexHttpPollingBehavior to cause polling to start, then polling will start by default when the channel is opened. The DuplexHttpPollingBehavior attribute can currently only be applied to service contract operations; applying it to callback contract operations will have no effect. It is not likely that a callback operation would be used to start polling because the callback operation message would never have made it to the client to begin with if polling was not already active. But more complex application scenarios that enable callback operations to either speed up or suspend polling might make sense. This will be left as an exercise for the developer using this sample channel. HttpPollingRequestChannel currently has some untested and therefore commented-out code to enable this functionality.

Message Batching
As described above, each HTTP request and reply does not correlate directly to an application message; the HTTP traffic simply provides the transport vehicle for the real application messages. As the service sends messages to the client, they get stored in the channels queue until an HTTP request is available to transport them to the client. If the service application is sending notifications to the client more frequently than the client channel is sending polling requests to pick them up, then multiple messages could exist in the service channels queue at any one time. It was described above that the client channel will send polling messages as quickly as it can while it knows that the service queue has messages waiting to go, but the channel can achieve even greater network efficiency and application responsiveness by packaging up multiple messages and sending them back to the client as a single HTTP reply. This is called message batching. Message batching is enabled via a binding property that is used by the services HttpPollingReplyChannel: MaxMessagesInBatch. When the service channel is preparing a reply, if there are 15 messages waiting to go in the queue and MaxMessagesInBatch is set to 10, then 10 of the messages will be removed from the queue and batched up into a single SOAP message to be sent to the client. The client channel (HttpPollingRequestChannel) is then responsible for converting the batch message back to the original 10 individual SOAP messages before returning them to the client application in response to the Receive() method being invoked. The client channel also has a queue, an inbound message queue, to facilitate this behavior. As described above, the client channel in this example will learn that there are 5 more messages waiting and will therefore immediately issue another polling request to pick them up. Message batching enables very high performance messaging scenarios. For example, if the service is firing notifications to the client in response to a real time hardware device, it could potentially be sending 50 or more messages per second. The client being connected over the internet - might only be able to get polling messages to the server every half second due to network latency. If the channel was only able to send one message per HTTP request, it would not be able to keep up with the applications performance requirements. Message batching solves this problem.

It is up to the application developer to set the MaxMessagesInBatch property appropriately based on the applications needs, the expected size of a typical application message and potentially other factors.

Server and Client Queue Throttles


Because there is not a one-to-one relationship between messages sent and received from the application and the actual HTTP network requests and replies, both the service channel (HttpPollingReplyChannel) and the client channel (HttpPollingRequestChannel) implement internal message queues. As the service is sending messages, they are being dropped into HttpPollingReplyChannels outbound queue to be picked up by the asynchronous logic that is processing incoming polling messages. If for some reason the client channel is not sending polling messages, then the number of messages in this queue would just continue to grow until the process runs out of memory. The application would potentially not know there was a problem. To mitigate this, the binding exposes the MaxUndeliveredMessages configuration property. When the queue reaches this configured maximum number of messages waiting to be delivered, then subsequent attempts to add more messages to the queue will simply wait until room is available. Eventually the Send() method will time out, and the application will learn there is a communication problem with the channel. It is the responsibility of the application developer to set this property to a value that makes sense for the application, given factors such as the expected polling frequency and the expected message frequency and the configured maximum number of messages that can be batched into a single reply. Conversely, the client channel has an input queue because inbound messages are only received as replies to HTTP requests and each reply could contain a batch of logical application messages. When the client application logic calls Receive() on the channel, it wants one application message. Receive() is implemented by simply reading the next available message from this input queue. Regardless of whether or not the application has called Receive() to pick up a message, the polling loop is sending requests and receiving one or more messages per reply and placing them in the queue. In the unlikely event that the application which is the WCF service model in most cases is not calling Receive() on the channel quickly enough, there is the potential that this inbound message queue could also get backlogged with unprocessed messages and become a memory leak on the client. HttpPollingRequestChannel has an internal throttle, implemented via the private field maxMessagesInQueue, which is arbitrarily set to 500. If the clients channel does get backlogged and reaches the max value, this will cause the client channel to fault. The included InputQueue class is used by both channels to implement their queues. It provides sophisticated multi-reader, multi-writer asynchronous message queuing and dequeuing capabilities. The InputQueue class is from the HttpCookieSession custom channel sample found on MSDN in the WCF documentation (Channels Extensibility Samples).

10

A Word about WCF Channels and Sessions


A WCF channel can either be sessionless or sessionful. Sessionful channels provide message correlation on the server, so that one instance of the channel will be created and kept alive for each client/connection. Messages received from the wire contain an indicator in the message that allows them to be routed to the correct channel instance. A sessionful channel is required in order to implement sessions at the service or application level. To learn more about the details of sessionful channels, refer to the WCF MSDN topic: Choosing a Message Exchange Pattern. In order to function properly, DuplexHttpBinding, like NetTcpBinding, needed to implement a sessionful channel stack. A sessionful channel stacks responsibilities include establishing a protocol between the client and the server to create and track a session identifier, instancing one channel stack per session on the server, managing the lifetime of the session, and routing the incoming messages to the correct channel stack instance. This is not a trivial task. Luckily, WCF ships a sessionful channel that works with the HttpTransport that can be used to implement sessions in the channel stack. Including the ReliableSessionBindingElement in the stack of BindingElements created by our binding injects the ReliableSession channel in the stack. Refer to the WCF MSDN topic: Creating a BindingElement to learn more about WCF BindingElements and their role in the channel model. Unfortunately, this ReliableSession channel introduces potentially unnecessary overhead because it also provides message ordering and guaranteed delivery capabilities, which translate into additional network traffic complicating efforts to minimize the polling traffic. Additionally, this reliable session channel does not work in partial trust and partial trust is a design requirement for DuplexHttpBinding. Therefore, in addition to the custom HTTP polling channel implementation, the sample application also includes a custom HTTP session channel implementation that does work in partial trust. This sample HTTP session channel is only a slightly modified version of the HttpCookieSession sample found in the WCF SDK on MSDN. Instead of using HTTP cookies, the HttpSession sample included here uses a custom SOAP header to track the session ID. The application developer using this sample code can choose to use either the included custom HttpSession channel, or WCFs ReliableSession channel. The DuplexHttpBinding has a Session configuration property that can be either set to HttpSession or ReliableSession. The only restriction is that both the client and the server must both use the same type of session.

DuplexHttpBinding Quick Reference


Client Binding Properties
DuplexHttpBinding.Session o Type: Microsoft.Samples.DuplexHttp.SessionType (enum) o Enum values: ReliableSession, HttpSession 11

Remarks: Sessions are required. Use the property to tell the binding to use either WCFs ReliableSession channel or the included custom HttpSession channel. Both the client channel and the server channel must use the same session type. DuplexHttpBinding.PollingInterval o Type: System.TimeSpan o Remarks: The default duration the client channel will wait after receiving a reply before sending another polling request. The actual polling interval is a combination of runtime factors. DuplexHttpBinding.PollingReplyInterval o Type: System.TimeSpan o Remarks: The duration the server will hold the polling request open while waiting for messages to send back to the client as the reply. Can be overridden by the server with the MaxPollingReplyInterval property. If this duration expires and there are still no messages to be sent to the client, the server will return an empty reply. The polling requests timeout property is coordinated with this duration such that if a reply is not received by the PollingReplyInterval plus 3 seconds (arbitrary, adjust in the sample code as needed), the polling request will time out and the channel will fault.

Server Binding Properties


DuplexHttpBinding.Session o Type: Microsoft.Samples.DuplexHttp.SessionType (enum) o Enum values: ReliableSession, HttpSession o Remarks: Sessions are required. Use the property to tell the binding to use either WCFs ReliableSession channel or the included custom HttpSession channel. Both the client channel and the server channel must use the same session type. DuplexHttpBinding.MaxUndeliveredMessages o Type: System.Int32 o Remarks: Maximum number of outbound messages that the channel will hold in its outbound message queue. If the client is not sending polling messages frequently enough, the outbound message queue will potentially become backed up. If there is no room in the queue, the Send() method will potentially time out while waiting for space. DuplexHttpBinding.MaxMessagesInBatch o Type: System.Int32 o Remarks: Maximum number of outbound messages that will be batched into a single reply. When the channel is preparing a reply message, if there is more than one message waiting in the outbound message queue they will be batched into a single message for transport to the client. DuplexHttpBinding.MaxPollingReplyInterval o Type: System.Int32 o Remarks: Maximum duration the channel will hold the HTTP polling request open while waiting for messages to be sent to the client as the reply. Note that only one

12

connection will be help open. If no messages are available when the duration expires, an empty reply will be sent back to the client.

DuplexHttpPollingBehavior
This is an attribute to be applied to operations on the service contract. It will trigger the channel to start or stop polling and optionally adjust the polling interval. If at least one operation is configured with this attribute as a start polling action, the client channel will not automatically start polling by default. It will instead wait for one of the polling start operations to be invoked before starting to send polling messages. If no operations on the service contract are configured as polling start operations, then the client channel will start polling by default when the channel is opened. The DuplexHttpPollingBehavior enables the channel to coordinate turning polling on and off with a typical subscribe/unsubscribe application metaphor. Properties: DuplexHttpPollingBehavior.PollingAction o Type: Microsoft.Samples.DuplexHttp.PollingAction (enum) o Enum values: Start, Stop, CorrelatedStop o Remarks: The PollingAction property is required and is provided in the constructor. Start will cause polling to start when the operation is invoked. Stop will cause polling to stop when the operation is invoked. CorrelatedStop will cause polling to stop when the operation is invoked if it was started by the operation(s) indicated in the StartAction property and there are no other outstanding start operations. DuplexHttpPollingBehavior.PollingInterval o Type: System.String o Remarks: Must be a valid string format that will parse to a System.TimeSpan. Relevant only if the PollingAction is Start. This is not a required parameter, but if provided, it will be used to fine tune the polling interval at runtime. If the current polling interval is longer than this duration, it will be sped up to this value. DuplexHttpPollingBehavior.StartAction o Type: System.String o Remarks: Semi-colon delimited list of server contract actions. Used in conjunction with the CorrelatedStop polling action. Each action can either be a fully qualified start action or an action shortened to just the method name.

Sample Server Configuration File


The following partial server config file sections are included here for reference:
<system.serviceModel> <extensions> <bindingExtensions> <add name="duplexHttpBinding" type="Microsoft.Samples.DuplexHttp.DuplexHttpBindingCollectionElement, DuplexHttpBinding, Version=0.0.0.0,

13

Culture=neutral, PublicKeyToken=null" /> </bindingExtensions> </extensions> <services> <service name="Microsoft.Samples.TestService.AlertService" behaviorConfiguration="AlertServiceBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost/AlertService"/> </baseAddresses> </host> <endpoint address="http://localhost/AlertService" binding="duplexHttpBinding" bindingConfiguration="partialTrustSession" contract="Microsoft.Samples.TestService.IAlertService" /> </service> </services> <bindings> <duplexHttpBinding> <binding name="partialTrustSession" session="HttpSession" sessionTimeout="00:10:00" maxUndeliveredMessages="100" maxMessagesInBatch="10" maxPollingReplyInterval="00:02:00"> </binding> </duplexHttpBinding> </bindings> </system.serviceModel>

Sample Client Configuration File


The following partial client config file sections are included here for reference:
<system.serviceModel> <extensions> <bindingExtensions> <add name="duplexHttpBinding" type="Microsoft.Samples.DuplexHttp.DuplexHttpBindingCollectionElement, DuplexHttpBinding, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" /> </bindingExtensions> </extensions> <client> <endpoint name="duplexHttpBinding_partialTrustSession" address="http://localhost/AlertService" binding="duplexHttpBinding" bindingConfiguration="partialTrustSession" contract="Microsoft.Samples.TestService.IAlertService" /> </client> <bindings> <duplexHttpBinding> <binding name="partialTrustSession" session="HttpSession" pollingInterval="00:00:04" pollingReplyInterval="00:01:00">

14

</binding> </duplexHttpBinding> </bindings> </system.serviceModel>

The Sample Application


The sample code includes a reference application that demonstrates how to use the custom DuplexHttpBinding. The reference application consists of an alert service, a service host application and a client application. The alert service provides a simple engine that enables clients to subscribe to and post alerts, which are simple string messages. The DuplexHttpAll.sln Visual Studio solution contains the following 5 projects: 1. DuplexHttpBinding: This builds the DuplexHttpBinding.dll, which contains the custom binding and channels. 2. AlertService: This contains the alert service implementation, which includes the AlertService web service and the Alerts engine. 3. AlertServiceContract: This builds the AlertServiceContract.dll. It includes the IAlertService and IAlertServiceCallback contracts. These service contracts are separated to their own assembly so they can be shared by the service and the client. 4. WindowsClient: This builds WindowsClient.exe, the alert client WPF application. 5. WindowsHost: This builds WindowsHost.exe, a WPF application that serves as the console for the alert service as well as the host process for the alert web service.

Quick Start
Run the Sample 0. Start Visual Studio on Vista using Run as Administrator (required for the service host application to listen for connections) 1. Press F5 in Visual Studio to launch both the WindowsClient and WindowsHost applications. 2. Click Create Proxy in the blue Alert Client application to connect with the alert service. 3. Click on the Red alert subscriptions check box to subscribe to red alerts. This first interaction with the service will open the channel and start polling. The trace output will indicate that polling messages are being sent to the service. 4. In the green Alert Server Console and Service Host application, click on the Post Red button. This will cause a red alert to be posted, and because the client is subscribed to red alerts, the new red alert will show up in the Red Alerts list box in the client. 5. In the client, click on the Yellow alert subscriptions check box to subscribe to yellow alerts. 6. In the client, enter a new yellow alert in the text box and click Post Yellow. This will post a new alert to the service. The alert you entered will show up in the Yellow Alerts list box in the green server console application and because the client is subscribed to yellow alerts, it will also show up in the Yellow Alerts list box on the client.

15

Things to Notice 1. Regular polling doesnt start (no trace messages) until the client subscribes to either red or yellow alerts. 2. If only yellow alerts are subscribed, polling messages will be sent from the server every 4 seconds. This is because the bindings default polling interval is set to 4 seconds. 3. If subscribed to red alerts, polling messages will be sent from the server every 1 second. This is because the SubscribeRed() server operation is configured to adjust the polling interval to 1 second. 4. Because the polling reply interval is set to 10 seconds, each polling message sent to the server will be held open by the channel for up to 10 seconds while waiting for any messages to be sent back to the client. If there is no activity, this will result in an additional 10 seconds between polling requests.

Alert Service
The alert service and callback contracts look like this:
public interface IAlertService { [OperationContract(IsOneWay=true) ] void PostAlert(AlertType type, string alert); [OperationContract] string[] GetAllAlerts(AlertType type); [OperationContract(IsOneWay = true)] [DuplexHttpPollingBehavior(PollingAction.Start)] void SubscribeYellow(); [OperationContract(IsOneWay = true)] [DuplexHttpPollingBehavior(PollingAction.CorrelatedStop,StartAction="SubscribeYellow")] void UnsubscribeYellow(); [OperationContract(IsOneWay = true)] [DuplexHttpPollingBehavior(PollingAction.Start,PollingInterval="00:00:01")] void SubscribeRed(); [OperationContract(IsOneWay = true)] [DuplexHttpPollingBehavior(PollingAction.CorrelatedStop,StartAction="SubscribeRed")] void UnsubscribeRed(); [OperationContract(IsOneWay = true)] [DuplexHttpPollingBehavior(PollingAction.Stop)] void UnsubscribeAll(); } public interface IAlertServiceCallback { [OperationContract(IsOneWay = true)] void AlertPosted(AlertType type, string alert); }

There are 2 types of alerts: yellow alerts and red alerts. A client can subscribe to either type independently. Because the SubscribeRed() method has a PollingInterval specified in the DuplexHttpPollingBehavior attribute, when a client application using the DuplexHttpBinding subscribes to red alerts the internal polling messages will speed up to a frequency of every 1 second (unless the

16

polling interval of course is already faster than 1 second.) When an alert is posted to the service, all subscribed clients will have their AlertPosted() callback method invoked. Instead of using SvcUtil.exe to generate a client proxy for the service, the client application uses WCFs generic DuplexChannelFactory class to create the client proxy. This was done simply to remove the extra developer step of invoking SvcUtil.exe to generate a new client proxy each time the interface was refactored during development. Client proxies can be generated with SvcUtil.exe for use with this binding. The app.config files for the WindowsClient and WindowsHost projects contain the WCF binding configuration settings as described above, but the user interfaces for the client and service applications enable all of these important settings to be adjusted as well.

WindowsHost

The WindowsHost application serves 2 purposes. It hosts the alert engine and it hosts the WCF alert service to provide client access to the alerts engine. In addition to hosting the alerts engine, it provides a user interface for the engine, essentially acting as a server side alerts console. Looking at the screen shot above, there are 3 main panes in the application: 1. Service Configuration Pane.

17

On the left is a pane that enables adjusting the WCF binding properties. All of these properties are described above in the Smart Polling section of this paper. When WindowsHost is started, it will automatically start the web service on 3 different endpoints, 2 of them listening on HTTP using the DuplexHttpBinding and one listening on TCP using WCFs NetTcpBinding. To change any of the binding properties via this interface, first stop the service using the Stop Service button. 2. Trace Output Pane. The service and channel Trace.WriteLine messages are piped to this pane. This text box is editable which can be convenient while testing the application and running the channel through various scenarios. 3. Alert Console The top right portion of the window contains the user interface for the alert engine. Enter an alert in either the red or yellow text box and click the appropriate post button to post the alert. As alerts are posted, they are displayed in either the Yellow Alerts or Red Alerts list box and the alert engine will fire an event indicating that an alert was posted. The hosted WCF alert service is subscribed to this alert engines event, the WCF alert service will respond by pushing the alert out to all subscribed clients, by invoking the AlertPosted() method on the callback contract.

WindowsClient

18

The alert client application provides the user interface to post and subscribe to alerts. It demonstrates all of the capabilities of the custom WCF channel except its ability to run in partial trust (because this is a full trust application). There are 3 main panes in the application: 1. Proxy Configuration. Use the Proxy Configuration panel to configure the settings used for connecting to the web service. First choose either the TCP (NetTcpBinding) or HTTP (DuplexHttpBinding) binding. If using the HTTP binding, choose which channel to use to provide session support. ReliableSession equates to WCFs ReliableSession channel and HttpSession causes the custom HttpSession channel to be used (read the section above on sessions to learn more about these choices). The Polling Interval and Polling Reply Interval settings are configured in seconds (read the section above on Smart Polling to understand their purpose). Click Create Proxy to generate a client proxy with the configured settings. To adjust the settings, close the proxy and create a new one after making the changes. 2. Trace Output. The client and channel Trace.WriteLine messages are piped to in this pane. This text box is editable which can be convenient while testing the application and running the channel through various scenarios. 3. Alert User Interface. After clicking Create Proxy, use the Post and Get buttons in the interface to interact with the alert service. To subscribe to either red or yellow alerts, check the appropriate Alert Subscriptions check box. The sample application is designed to demonstrate the channels abilities to invoke request/reply methods on a service, invoke one-way messages on a service and support one-way callbacks from the service. It does not demonstrate callback methods that return a reply value to the sender.

Silverlight 2 and Duplex Over HTTP.


As of this writing, Silverlight 2 Beta 2 is shipping with a WCF channel that enables the duplex message exchange pattern over HTTP. The client binding PollingDuplexHttpBinding - will be included in the Silverlight plug-in. The Silverlight SDK contains a .NET 3.5 channel for use by the service. Please refer to the Silverlight SDK for more details on how to use this channel. This Silverlight solution does not currently include a client channel for .NET clients. Although similarly named DuplexHttpBinding and PollingDuplexHttpBinding, these 2 channels were developed independently. DuplexHttpBinding is provided as sample code demonstrating how to solve this problem by extending the WCF channel model, it has a different API and different capabilities from the Silverlight channel that is soon to be shipping with Silverlight. Like the DuplexHttpBindings channels, this new Silverlight channel is an IDuplexChannel so it will be able to be used in place of this sample code if it eventually shows up in the .NET framework.

19

Additional Resources
Duplex programming in WCF: http://msdn.microsoft.com/en-us/library/ms731064.aspx WCF Channel Model Overview: http://msdn.microsoft.com/en-us/library/ms729840.aspx Duplex Services in Silverlight: http://msdn.microsoft.com/en-us/library/cc645026(VS.95).aspx Comet Long Polling : http://en.wikipedia.org/wiki/Comet_%28programming%29

20

You might also like